1 // Written in the D programming language.
2 
3 /**
4 This is a submodule of $(MREF std, math).
5 
6 It contains several exponential and logarithm functions.
7 
8 Copyright: Copyright The D Language Foundation 2000 - 2011.
9            D implementations of exp, expm1, exp2, log, log10, log1p, and log2
10            functions are based on the CEPHES math library, which is Copyright
11            (C) 2001 Stephen L. Moshier $(LT)steve@moshier.net$(GT) and are
12            incorporated herein by permission of the author. The author reserves
13            the right to distribute this material elsewhere under different
14            copying permissions. These modifications are distributed here under
15            the following terms:
16 License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
17 Authors:   $(HTTP digitalmars.com, Walter Bright), Don Clugston,
18            Conversion of CEPHES math library to D by Iain Buclaw and David Nadlinger
19 Source: $(PHOBOSSRC std/math/exponential.d)
20 
21 Macros:
22     TABLE_SV = <table border="1" cellpadding="4" cellspacing="0">
23                <caption>Special Values</caption>
24                $0</table>
25     NAN = $(RED NAN)
26     PLUSMN = &plusmn;
27     INFIN = &infin;
28     PLUSMNINF = &plusmn;&infin;
29     LT = &lt;
30     GT = &gt;
31  */
32 
33 module std.math.exponential;
34 
35 import std.traits :  isFloatingPoint, isIntegral, isSigned, isUnsigned, Largest, Unqual;
36 
37 static import core.math;
38 static import core.stdc.math;
39 
40 version (DigitalMars)
41 {
42     version = INLINE_YL2X;        // x87 has opcodes for these
43 }
44 
45 version (D_InlineAsm_X86)    version = InlineAsm_X86_Any;
46 version (D_InlineAsm_X86_64) version = InlineAsm_X86_Any;
47 
48 version (InlineAsm_X86_Any) version = InlineAsm_X87;
49 version (InlineAsm_X87)
50 {
51     version (CRuntime_Microsoft) version = InlineAsm_X87_MSVC;
52     else static assert(real.mant_dig == 64);
53 }
54 
55 version (D_HardFloat)
56 {
57     // FloatingPointControl.clearExceptions() depends on version IeeeFlagsSupport
58     version (IeeeFlagsSupport) version = FloatingPointControlSupport;
59 }
60 
61 /**
62  * Compute the value of x $(SUPERSCRIPT n), where n is an integer
63  */
64 Unqual!F pow(F, G)(F x, G n) @nogc @trusted pure nothrow
65 if (isFloatingPoint!(F) && isIntegral!(G))
66 {
67     import std.traits : Unsigned;
68 
69     real p = 1.0, v = void;
70     Unsigned!(Unqual!G) m = n;
71 
72     if (n < 0)
73     {
74         if (n == -1) return 1 / x;
75 
76         m = cast(typeof(m))(0 - n);
77         v = p / x;
78     }
79     else
80     {
81         switch (n)
82         {
83         case 0:
84             return 1.0;
85         case 1:
86             return x;
87         case 2:
88             return x * x;
89         default:
90         }
91 
92         v = x;
93     }
94 
95     while (1)
96     {
97         if (m & 1)
98             p *= v;
99         m >>= 1;
100         if (!m)
101             break;
102         v *= v;
103     }
104     return p;
105 }
106 
107 ///
108 @safe pure nothrow @nogc unittest
109 {
110     import std.math.operations : feqrel;
111 
112     assert(pow(2.0, 5) == 32.0);
113     assert(pow(1.5, 9).feqrel(38.4433) > 16);
114     assert(pow(real.nan, 2) is real.nan);
115     assert(pow(real.infinity, 2) == real.infinity);
116 }
117 
118 @safe pure nothrow @nogc unittest
119 {
120     import std.math.operations : isClose, feqrel;
121 
122     // Make sure it instantiates and works properly on immutable values and
123     // with various integer and float types.
124     immutable real x = 46;
125     immutable float xf = x;
126     immutable double xd = x;
127     immutable uint one = 1;
128     immutable ushort two = 2;
129     immutable ubyte three = 3;
130     immutable ulong eight = 8;
131 
132     immutable int neg1 = -1;
133     immutable short neg2 = -2;
134     immutable byte neg3 = -3;
135     immutable long neg8 = -8;
136 
137 
138     assert(pow(x,0) == 1.0);
139     assert(pow(xd,one) == x);
140     assert(pow(xf,two) == x * x);
141     assert(pow(x,three) == x * x * x);
142     assert(pow(x,eight) == (x * x) * (x * x) * (x * x) * (x * x));
143 
144     assert(pow(x, neg1) == 1 / x);
145 
146     assert(isClose(pow(xd, neg2), cast(double) (1 / (x * x)), 1e-15));
147     assert(isClose(pow(xf, neg8), cast(float) (1 / ((x * x) * (x * x) * (x * x) * (x * x))), 1e-15));
148 
149     assert(feqrel(pow(x, neg3),  1 / (x * x * x)) >= real.mant_dig - 1);
150 }
151 
152 @safe @nogc nothrow unittest
153 {
154     import std.math.operations : isClose;
155 
156     assert(isClose(pow(2.0L, 10L), 1024, 1e-18));
157 }
158 
159 // https://issues.dlang.org/show_bug.cgi?id=21601
160 @safe @nogc nothrow pure unittest
161 {
162     // When reals are large enough the results of pow(b, e) can be
163     // calculated correctly, if b is of type float or double and e is
164     // not too large.
165     static if (real.mant_dig >= 64)
166     {
167         // expected result: 3.790e-42
168         assert(pow(-513645318757045764096.0f, -2) > 0.0);
169 
170         // expected result: 3.763915357831797e-309
171         assert(pow(-1.6299717435255677e+154, -2) > 0.0);
172     }
173 }
174 
175 @safe @nogc nothrow unittest
176 {
177     import std.math.operations : isClose;
178     import std.math.traits : isInfinity;
179 
180     static float f1 = 19100.0f;
181     static float f2 = 0.000012f;
182 
183     assert(isClose(pow(f1,9), 3.3829868e+38f));
184     assert(isInfinity(pow(f1,10)));
185     assert(pow(f2,9) > 0.0f);
186     assert(isClose(pow(f2,10), 0.0f, 0.0, float.min_normal));
187 
188     static double d1 = 21800.0;
189     static double d2 = 0.000012;
190 
191     assert(isClose(pow(d1,71), 1.0725339442974e+308));
192     assert(isInfinity(pow(d1,72)));
193     assert(pow(d2,65) > 0.0f);
194     assert(isClose(pow(d2,66), 0.0, 0.0, double.min_normal));
195 
196     static if (real.mant_dig == 64) // x87
197     {
198         static real r1 = 21950.0L;
199         static real r2 = 0.000011L;
200 
201         assert(isClose(pow(r1,1136), 7.4066175654969242752260330529e+4931L));
202         assert(isInfinity(pow(r1,1137)));
203         assert(pow(r2,998) > 0.0L);
204         assert(isClose(pow(r2,999), 0.0L, 0.0, real.min_normal));
205     }
206 }
207 
208 @safe @nogc nothrow pure unittest
209 {
210     import std.math.operations : isClose;
211 
212     enum f1 = 19100.0f;
213     enum f2 = 0.000012f;
214 
215     static assert(isClose(pow(f1,9), 3.3829868e+38f));
216     static assert(pow(f1,10) > float.max);
217     static assert(pow(f2,9) > 0.0f);
218     static assert(isClose(pow(f2,10), 0.0f, 0.0, float.min_normal));
219 
220     enum d1 = 21800.0;
221     enum d2 = 0.000012;
222 
223     static assert(isClose(pow(d1,71), 1.0725339442974e+308));
224     static assert(pow(d1,72) > double.max);
225     static assert(pow(d2,65) > 0.0f);
226     static assert(isClose(pow(d2,66), 0.0, 0.0, double.min_normal));
227 
228     static if (real.mant_dig == 64) // x87
229     {
230         enum r1 = 21950.0L;
231         enum r2 = 0.000011L;
232 
233         static assert(isClose(pow(r1,1136), 7.4066175654969242752260330529e+4931L));
234         static assert(pow(r1,1137) > real.max);
235         static assert(pow(r2,998) > 0.0L);
236         static assert(isClose(pow(r2,999), 0.0L, 0.0, real.min_normal));
237     }
238 }
239 
240 /**
241  * Compute the power of two integral numbers.
242  *
243  * Params:
244  *     x = base
245  *     n = exponent
246  *
247  * Returns:
248  *     x raised to the power of n. If n is negative the result is 1 / pow(x, -n),
249  *     which is calculated as integer division with remainder. This may result in
250  *     a division by zero error.
251  *
252  *     If both x and n are 0, the result is 1.
253  *
254  * Throws:
255  *     If x is 0 and n is negative, the result is the same as the result of a
256  *     division by zero.
257  */
258 typeof(Unqual!(F).init * Unqual!(G).init) pow(F, G)(F x, G n) @nogc @trusted pure nothrow
259 if (isIntegral!(F) && isIntegral!(G))
260 {
261     import std.traits : isSigned;
262 
263     typeof(return) p, v = void;
264     Unqual!G m = n;
265 
266     static if (isSigned!(F))
267     {
268         if (x == -1) return cast(typeof(return)) (m & 1 ? -1 : 1);
269     }
270     static if (isSigned!(G))
271     {
272         if (x == 0 && m <= -1) return x / 0;
273     }
274     if (x == 1) return 1;
275     static if (isSigned!(G))
276     {
277         if (m < 0) return 0;
278     }
279 
280     switch (m)
281     {
282     case 0:
283         p = 1;
284         break;
285 
286     case 1:
287         p = x;
288         break;
289 
290     case 2:
291         p = x * x;
292         break;
293 
294     default:
295         v = x;
296         p = 1;
297         while (1)
298         {
299             if (m & 1)
300                 p *= v;
301             m >>= 1;
302             if (!m)
303                 break;
304             v *= v;
305         }
306         break;
307     }
308     return p;
309 }
310 
311 ///
312 @safe pure nothrow @nogc unittest
313 {
314     assert(pow(2, 3) == 8);
315     assert(pow(3, 2) == 9);
316 
317     assert(pow(2, 10) == 1_024);
318     assert(pow(2, 20) == 1_048_576);
319     assert(pow(2, 30) == 1_073_741_824);
320 
321     assert(pow(0, 0) == 1);
322 
323     assert(pow(1, -5) == 1);
324     assert(pow(1, -6) == 1);
325     assert(pow(-1, -5) == -1);
326     assert(pow(-1, -6) == 1);
327 
328     assert(pow(-2, 5) == -32);
329     assert(pow(-2, -5) == 0);
330     assert(pow(cast(double) -2, -5) == -0.03125);
331 }
332 
333 @safe pure nothrow @nogc unittest
334 {
335     immutable int one = 1;
336     immutable byte two = 2;
337     immutable ubyte three = 3;
338     immutable short four = 4;
339     immutable long ten = 10;
340 
341     assert(pow(two, three) == 8);
342     assert(pow(two, ten) == 1024);
343     assert(pow(one, ten) == 1);
344     assert(pow(ten, four) == 10_000);
345     assert(pow(four, 10) == 1_048_576);
346     assert(pow(three, four) == 81);
347 }
348 
349 // https://issues.dlang.org/show_bug.cgi?id=7006
350 @safe pure nothrow @nogc unittest
351 {
352     assert(pow(5, -1) == 0);
353     assert(pow(-5, -1) == 0);
354     assert(pow(5, -2) == 0);
355     assert(pow(-5, -2) == 0);
356     assert(pow(-1, int.min) == 1);
357     assert(pow(-2, int.min) == 0);
358 
359     assert(pow(4294967290UL,2) == 18446744022169944100UL);
360     assert(pow(0,uint.max) == 0);
361 }
362 
363 /**Computes integer to floating point powers.*/
364 real pow(I, F)(I x, F y) @nogc @trusted pure nothrow
365 if (isIntegral!I && isFloatingPoint!F)
366 {
367     return pow(cast(real) x, cast(Unqual!F) y);
368 }
369 
370 ///
371 @safe pure nothrow @nogc unittest
372 {
373     assert(pow(2, 5.0) == 32.0);
374     assert(pow(7, 3.0) == 343.0);
375     assert(pow(2, real.nan) is real.nan);
376     assert(pow(2, real.infinity) == real.infinity);
377 }
378 
379 /**
380  * Calculates x$(SUPERSCRIPT y).
381  *
382  * $(TABLE_SV
383  * $(TR $(TH x) $(TH y) $(TH pow(x, y))
384  *      $(TH div 0) $(TH invalid?))
385  * $(TR $(TD anything)      $(TD $(PLUSMN)0.0)                $(TD 1.0)
386  *      $(TD no)        $(TD no) )
387  * $(TR $(TD |x| $(GT) 1)    $(TD +$(INFIN))                  $(TD +$(INFIN))
388  *      $(TD no)        $(TD no) )
389  * $(TR $(TD |x| $(LT) 1)    $(TD +$(INFIN))                  $(TD +0.0)
390  *      $(TD no)        $(TD no) )
391  * $(TR $(TD |x| $(GT) 1)    $(TD -$(INFIN))                  $(TD +0.0)
392  *      $(TD no)        $(TD no) )
393  * $(TR $(TD |x| $(LT) 1)    $(TD -$(INFIN))                  $(TD +$(INFIN))
394  *      $(TD no)        $(TD no) )
395  * $(TR $(TD +$(INFIN))      $(TD $(GT) 0.0)                  $(TD +$(INFIN))
396  *      $(TD no)        $(TD no) )
397  * $(TR $(TD +$(INFIN))      $(TD $(LT) 0.0)                  $(TD +0.0)
398  *      $(TD no)        $(TD no) )
399  * $(TR $(TD -$(INFIN))      $(TD odd integer $(GT) 0.0)      $(TD -$(INFIN))
400  *      $(TD no)        $(TD no) )
401  * $(TR $(TD -$(INFIN))      $(TD $(GT) 0.0, not odd integer) $(TD +$(INFIN))
402  *      $(TD no)        $(TD no))
403  * $(TR $(TD -$(INFIN))      $(TD odd integer $(LT) 0.0)      $(TD -0.0)
404  *      $(TD no)        $(TD no) )
405  * $(TR $(TD -$(INFIN))      $(TD $(LT) 0.0, not odd integer) $(TD +0.0)
406  *      $(TD no)        $(TD no) )
407  * $(TR $(TD $(PLUSMN)1.0)   $(TD $(PLUSMN)$(INFIN))          $(TD -$(NAN))
408  *      $(TD no)        $(TD yes) )
409  * $(TR $(TD $(LT) 0.0)      $(TD finite, nonintegral)        $(TD $(NAN))
410  *      $(TD no)        $(TD yes))
411  * $(TR $(TD $(PLUSMN)0.0)   $(TD odd integer $(LT) 0.0)      $(TD $(PLUSMNINF))
412  *      $(TD yes)       $(TD no) )
413  * $(TR $(TD $(PLUSMN)0.0)   $(TD $(LT) 0.0, not odd integer) $(TD +$(INFIN))
414  *      $(TD yes)       $(TD no))
415  * $(TR $(TD $(PLUSMN)0.0)   $(TD odd integer $(GT) 0.0)      $(TD $(PLUSMN)0.0)
416  *      $(TD no)        $(TD no) )
417  * $(TR $(TD $(PLUSMN)0.0)   $(TD $(GT) 0.0, not odd integer) $(TD +0.0)
418  *      $(TD no)        $(TD no) )
419  * )
420  */
421 Unqual!(Largest!(F, G)) pow(F, G)(F x, G y) @nogc @trusted pure nothrow
422 if (isFloatingPoint!(F) && isFloatingPoint!(G))
423 {
424     import core.math : fabs, sqrt;
425     import std.math.traits : isInfinity, isNaN, signbit;
426 
427     alias Float = typeof(return);
428 
429     static real impl(real x, real y) @nogc pure nothrow
430     {
431         // Special cases.
432         if (isNaN(y))
433             return y;
434         if (isNaN(x) && y != 0.0)
435             return x;
436 
437         // Even if x is NaN.
438         if (y == 0.0)
439             return 1.0;
440         if (y == 1.0)
441             return x;
442 
443         if (isInfinity(y))
444         {
445             if (isInfinity(x))
446             {
447                 if (!signbit(y) && !signbit(x))
448                     return F.infinity;
449                 else
450                     return F.nan;
451             }
452             else if (fabs(x) > 1)
453             {
454                 if (signbit(y))
455                     return +0.0;
456                 else
457                     return F.infinity;
458             }
459             else if (fabs(x) == 1)
460             {
461                 return F.nan;
462             }
463             else // < 1
464             {
465                 if (signbit(y))
466                     return F.infinity;
467                 else
468                     return +0.0;
469             }
470         }
471         if (isInfinity(x))
472         {
473             if (signbit(x))
474             {
475                 long i = cast(long) y;
476                 if (y > 0.0)
477                 {
478                     if (i == y && i & 1)
479                         return -F.infinity;
480                     else if (i == y)
481                         return F.infinity;
482                     else
483                         return -F.nan;
484                 }
485                 else if (y < 0.0)
486                 {
487                     if (i == y && i & 1)
488                         return -0.0;
489                     else if (i == y)
490                         return +0.0;
491                     else
492                         return F.nan;
493                 }
494             }
495             else
496             {
497                 if (y > 0.0)
498                     return F.infinity;
499                 else if (y < 0.0)
500                     return +0.0;
501             }
502         }
503 
504         if (x == 0.0)
505         {
506             if (signbit(x))
507             {
508                 long i = cast(long) y;
509                 if (y > 0.0)
510                 {
511                     if (i == y && i & 1)
512                         return -0.0;
513                     else
514                         return +0.0;
515                 }
516                 else if (y < 0.0)
517                 {
518                     if (i == y && i & 1)
519                         return -F.infinity;
520                     else
521                         return F.infinity;
522                 }
523             }
524             else
525             {
526                 if (y > 0.0)
527                     return +0.0;
528                 else if (y < 0.0)
529                     return F.infinity;
530             }
531         }
532         if (x == 1.0)
533             return 1.0;
534 
535         if (y >= F.max)
536         {
537             if ((x > 0.0 && x < 1.0) || (x > -1.0 && x < 0.0))
538                 return 0.0;
539             if (x > 1.0 || x < -1.0)
540                 return F.infinity;
541         }
542         if (y <= -F.max)
543         {
544             if ((x > 0.0 && x < 1.0) || (x > -1.0 && x < 0.0))
545                 return F.infinity;
546             if (x > 1.0 || x < -1.0)
547                 return 0.0;
548         }
549 
550         if (x >= F.max)
551         {
552             if (y > 0.0)
553                 return F.infinity;
554             else
555                 return 0.0;
556         }
557         if (x <= -F.max)
558         {
559             long i = cast(long) y;
560             if (y > 0.0)
561             {
562                 if (i == y && i & 1)
563                     return -F.infinity;
564                 else
565                     return F.infinity;
566             }
567             else if (y < 0.0)
568             {
569                 if (i == y && i & 1)
570                     return -0.0;
571                 else
572                     return +0.0;
573             }
574         }
575 
576         // Integer power of x.
577         long iy = cast(long) y;
578         if (iy == y && fabs(y) < 32_768.0)
579             return pow(x, iy);
580 
581         real sign = 1.0;
582         if (x < 0)
583         {
584             // Result is real only if y is an integer
585             // Check for a non-zero fractional part
586             enum maxOdd = pow(2.0L, real.mant_dig) - 1.0L;
587             static if (maxOdd > ulong.max)
588             {
589                 // Generic method, for any FP type
590                 import std.math.rounding : floor;
591                 if (floor(y) != y)
592                     return sqrt(x); // Complex result -- create a NaN
593 
594                 const hy = 0.5 * y;
595                 if (floor(hy) != hy)
596                     sign = -1.0;
597             }
598             else
599             {
600                 // Much faster, if ulong has enough precision
601                 const absY = fabs(y);
602                 if (absY <= maxOdd)
603                 {
604                     const uy = cast(ulong) absY;
605                     if (uy != absY)
606                         return sqrt(x); // Complex result -- create a NaN
607 
608                     if (uy & 1)
609                         sign = -1.0;
610                 }
611             }
612             x = -x;
613         }
614         version (INLINE_YL2X)
615         {
616             // If x > 0, x ^^ y == 2 ^^ ( y * log2(x) )
617             // TODO: This is not accurate in practice. A fast and accurate
618             // (though complicated) method is described in:
619             // "An efficient rounding boundary test for pow(x, y)
620             // in double precision", C.Q. Lauter and V. Lefèvre, INRIA (2007).
621             return sign * exp2( core.math.yl2x(x, y) );
622         }
623         else
624         {
625             // If x > 0, x ^^ y == 2 ^^ ( y * log2(x) )
626             // TODO: This is not accurate in practice. A fast and accurate
627             // (though complicated) method is described in:
628             // "An efficient rounding boundary test for pow(x, y)
629             // in double precision", C.Q. Lauter and V. Lefèvre, INRIA (2007).
630             Float w = exp2(y * log2(x));
631             return sign * w;
632         }
633     }
634     return impl(x, y);
635 }
636 
637 ///
638 @safe pure nothrow @nogc unittest
639 {
640     import std.math.operations : isClose;
641 
642     assert(isClose(pow(2.0, 3.0), 8.0));
643     assert(isClose(pow(1.5, 10.0), 57.6650390625));
644 
645     // square root of 9
646     assert(isClose(pow(9.0, 0.5), 3.0));
647     // 10th root of 1024
648     assert(isClose(pow(1024.0, 0.1), 2.0));
649 
650     assert(isClose(pow(-4.0, 3.0), -64.0));
651 
652     // reciprocal of 4 ^^ 2
653     assert(isClose(pow(4.0, -2.0), 0.0625));
654     // reciprocal of (-2) ^^ 3
655     assert(isClose(pow(-2.0, -3.0), -0.125));
656 
657     assert(isClose(pow(-2.5, 3.0), -15.625));
658     // reciprocal of 2.5 ^^ 3
659     assert(isClose(pow(2.5, -3.0), 0.064));
660     // reciprocal of (-2.5) ^^ 3
661     assert(isClose(pow(-2.5, -3.0), -0.064));
662 
663     // reciprocal of square root of 4
664     assert(isClose(pow(4.0, -0.5), 0.5));
665 
666     // per definition
667     assert(isClose(pow(0.0, 0.0), 1.0));
668 }
669 
670 ///
671 @safe pure nothrow @nogc unittest
672 {
673     import std.math.operations : isClose;
674 
675     // the result is a complex number
676     // which cannot be represented as floating point number
677     import std.math.traits : isNaN;
678     assert(isNaN(pow(-2.5, -1.5)));
679 
680     // use the ^^-operator of std.complex instead
681     import std.complex : complex;
682     auto c1 = complex(-2.5, 0.0);
683     auto c2 = complex(-1.5, 0.0);
684     auto result = c1 ^^ c2;
685     // exact result apparently depends on `real` precision => increased tolerance
686     assert(isClose(result.re, -4.64705438e-17, 2e-4));
687     assert(isClose(result.im, 2.52982e-1, 2e-4));
688 }
689 
690 @safe pure nothrow @nogc unittest
691 {
692     import std.math.traits : isNaN;
693 
694     assert(pow(1.5, real.infinity) == real.infinity);
695     assert(pow(0.5, real.infinity) == 0.0);
696     assert(pow(1.5, -real.infinity) == 0.0);
697     assert(pow(0.5, -real.infinity) == real.infinity);
698     assert(pow(real.infinity, 1.0) == real.infinity);
699     assert(pow(real.infinity, -1.0) == 0.0);
700     assert(pow(real.infinity, real.infinity) == real.infinity);
701     assert(pow(-real.infinity, 1.0) == -real.infinity);
702     assert(pow(-real.infinity, 2.0) == real.infinity);
703     assert(pow(-real.infinity, -1.0) == -0.0);
704     assert(pow(-real.infinity, -2.0) == 0.0);
705     assert(isNaN(pow(1.0, real.infinity)));
706     assert(pow(0.0, -1.0) == real.infinity);
707     assert(pow(real.nan, 0.0) == 1.0);
708     assert(isNaN(pow(real.nan, 3.0)));
709     assert(isNaN(pow(3.0, real.nan)));
710 }
711 
712 @safe @nogc nothrow unittest
713 {
714     import std.math.operations : isClose;
715 
716     assert(isClose(pow(2.0L, 10.0L), 1024, 1e-18));
717 }
718 
719 @safe pure nothrow @nogc unittest
720 {
721     import std.math.operations : isClose;
722     import std.math.traits : isIdentical, isNaN;
723     import std.math.constants : PI;
724 
725     // Test all the special values.  These unittests can be run on Windows
726     // by temporarily changing the version (linux) to version (all).
727     immutable float zero = 0;
728     immutable real one = 1;
729     immutable double two = 2;
730     immutable float three = 3;
731     immutable float fnan = float.nan;
732     immutable double dnan = double.nan;
733     immutable real rnan = real.nan;
734     immutable dinf = double.infinity;
735     immutable rninf = -real.infinity;
736 
737     assert(pow(fnan, zero) == 1);
738     assert(pow(dnan, zero) == 1);
739     assert(pow(rnan, zero) == 1);
740 
741     assert(pow(two, dinf) == double.infinity);
742     assert(isIdentical(pow(0.2f, dinf), +0.0));
743     assert(pow(0.99999999L, rninf) == real.infinity);
744     assert(isIdentical(pow(1.000000001, rninf), +0.0));
745     assert(pow(dinf, 0.001) == dinf);
746     assert(isIdentical(pow(dinf, -0.001), +0.0));
747     assert(pow(rninf, 3.0L) == rninf);
748     assert(pow(rninf, 2.0L) == real.infinity);
749     assert(isIdentical(pow(rninf, -3.0), -0.0));
750     assert(isIdentical(pow(rninf, -2.0), +0.0));
751 
752     // @@@BUG@@@ somewhere
753     version (OSX) {} else assert(isNaN(pow(one, dinf)));
754     version (OSX) {} else assert(isNaN(pow(-one, dinf)));
755     assert(isNaN(pow(-0.2, PI)));
756     // boundary cases. Note that epsilon == 2^^-n for some n,
757     // so 1/epsilon == 2^^n is always even.
758     assert(pow(-1.0L, 1/real.epsilon - 1.0L) == -1.0L);
759     assert(pow(-1.0L, 1/real.epsilon) == 1.0L);
760     assert(isNaN(pow(-1.0L, 1/real.epsilon-0.5L)));
761     assert(isNaN(pow(-1.0L, -1/real.epsilon+0.5L)));
762 
763     assert(pow(0.0, -3.0) == double.infinity);
764     assert(pow(-0.0, -3.0) == -double.infinity);
765     assert(pow(0.0, -PI) == double.infinity);
766     assert(pow(-0.0, -PI) == double.infinity);
767     assert(isIdentical(pow(0.0, 5.0), 0.0));
768     assert(isIdentical(pow(-0.0, 5.0), -0.0));
769     assert(isIdentical(pow(0.0, 6.0), 0.0));
770     assert(isIdentical(pow(-0.0, 6.0), 0.0));
771 
772     // https://issues.dlang.org/show_bug.cgi?id=14786 fixed
773     immutable real maxOdd = pow(2.0L, real.mant_dig) - 1.0L;
774     assert(pow(-1.0L,  maxOdd) == -1.0L);
775     assert(pow(-1.0L, -maxOdd) == -1.0L);
776     assert(pow(-1.0L, maxOdd + 1.0L) == 1.0L);
777     assert(pow(-1.0L, -maxOdd + 1.0L) == 1.0L);
778     assert(pow(-1.0L, maxOdd - 1.0L) == 1.0L);
779     assert(pow(-1.0L, -maxOdd - 1.0L) == 1.0L);
780 
781     // Now, actual numbers.
782     assert(isClose(pow(two, three), 8.0));
783     assert(isClose(pow(two, -2.5), 0.1767766953));
784 
785     // Test integer to float power.
786     immutable uint twoI = 2;
787     assert(isClose(pow(twoI, three), 8.0));
788 }
789 
790 // https://issues.dlang.org/show_bug.cgi?id=20508
791 @safe pure nothrow @nogc unittest
792 {
793     import std.math.traits : isNaN;
794 
795     assert(isNaN(pow(-double.infinity, 0.5)));
796 
797     assert(isNaN(pow(-real.infinity, real.infinity)));
798     assert(isNaN(pow(-real.infinity, -real.infinity)));
799     assert(isNaN(pow(-real.infinity, 1.234)));
800     assert(isNaN(pow(-real.infinity, -0.751)));
801     assert(pow(-real.infinity, 0.0) == 1.0);
802 }
803 
804 /** Computes the value of a positive integer `x`, raised to the power `n`, modulo `m`.
805  *
806  *  Params:
807  *      x = base
808  *      n = exponent
809  *      m = modulus
810  *
811  *  Returns:
812  *      `x` to the power `n`, modulo `m`.
813  *      The return type is the largest of `x`'s and `m`'s type.
814  *
815  * The function requires that all values have unsigned types.
816  */
817 Unqual!(Largest!(F, H)) powmod(F, G, H)(F x, G n, H m)
818 if (isUnsigned!F && isUnsigned!G && isUnsigned!H)
819 {
820     import std.meta : AliasSeq;
821 
822     alias T = Unqual!(Largest!(F, H));
823     static if (T.sizeof <= 4)
824     {
825         alias DoubleT = AliasSeq!(void, ushort, uint, void, ulong)[T.sizeof];
826     }
827 
828     static T mulmod(T a, T b, T c)
829     {
830         static if (T.sizeof == 8)
831         {
832             static T addmod(T a, T b, T c)
833             {
834                 b = c - b;
835                 if (a >= b)
836                     return a - b;
837                 else
838                     return c - b + a;
839             }
840 
841             T result = 0, tmp;
842 
843             b %= c;
844             while (a > 0)
845             {
846                 if (a & 1)
847                     result = addmod(result, b, c);
848 
849                 a >>= 1;
850                 b = addmod(b, b, c);
851             }
852 
853             return result;
854         }
855         else
856         {
857             DoubleT result = cast(DoubleT) (cast(DoubleT) a * cast(DoubleT) b);
858             return result % c;
859         }
860     }
861 
862     T base = x, result = 1, modulus = m;
863     Unqual!G exponent = n;
864 
865     while (exponent > 0)
866     {
867         if (exponent & 1)
868             result = mulmod(result, base, modulus);
869 
870         base = mulmod(base, base, modulus);
871         exponent >>= 1;
872     }
873 
874     return result;
875 }
876 
877 ///
878 @safe pure nothrow @nogc unittest
879 {
880     assert(powmod(1U, 10U, 3U) == 1);
881     assert(powmod(3U, 2U, 6U) == 3);
882     assert(powmod(5U, 5U, 15U) == 5);
883     assert(powmod(2U, 3U, 5U) == 3);
884     assert(powmod(2U, 4U, 5U) == 1);
885     assert(powmod(2U, 5U, 5U) == 2);
886 }
887 
888 @safe pure nothrow @nogc unittest
889 {
890     ulong a = 18446744073709551615u, b = 20u, c = 18446744073709551610u;
891     assert(powmod(a, b, c) == 95367431640625u);
892     a = 100; b = 7919; c = 18446744073709551557u;
893     assert(powmod(a, b, c) == 18223853583554725198u);
894     a = 117; b = 7919; c = 18446744073709551557u;
895     assert(powmod(a, b, c) == 11493139548346411394u);
896     a = 134; b = 7919; c = 18446744073709551557u;
897     assert(powmod(a, b, c) == 10979163786734356774u);
898     a = 151; b = 7919; c = 18446744073709551557u;
899     assert(powmod(a, b, c) == 7023018419737782840u);
900     a = 168; b = 7919; c = 18446744073709551557u;
901     assert(powmod(a, b, c) == 58082701842386811u);
902     a = 185; b = 7919; c = 18446744073709551557u;
903     assert(powmod(a, b, c) == 17423478386299876798u);
904     a = 202; b = 7919; c = 18446744073709551557u;
905     assert(powmod(a, b, c) == 5522733478579799075u);
906     a = 219; b = 7919; c = 18446744073709551557u;
907     assert(powmod(a, b, c) == 15230218982491623487u);
908     a = 236; b = 7919; c = 18446744073709551557u;
909     assert(powmod(a, b, c) == 5198328724976436000u);
910 
911     a = 0; b = 7919; c = 18446744073709551557u;
912     assert(powmod(a, b, c) == 0);
913     a = 123; b = 0; c = 18446744073709551557u;
914     assert(powmod(a, b, c) == 1);
915 
916     immutable ulong a1 = 253, b1 = 7919, c1 = 18446744073709551557u;
917     assert(powmod(a1, b1, c1) == 3883707345459248860u);
918 
919     uint x = 100 ,y = 7919, z = 1844674407u;
920     assert(powmod(x, y, z) == 1613100340u);
921     x = 134; y = 7919; z = 1844674407u;
922     assert(powmod(x, y, z) == 734956622u);
923     x = 151; y = 7919; z = 1844674407u;
924     assert(powmod(x, y, z) == 1738696945u);
925     x = 168; y = 7919; z = 1844674407u;
926     assert(powmod(x, y, z) == 1247580927u);
927     x = 185; y = 7919; z = 1844674407u;
928     assert(powmod(x, y, z) == 1293855176u);
929     x = 202; y = 7919; z = 1844674407u;
930     assert(powmod(x, y, z) == 1566963682u);
931     x = 219; y = 7919; z = 1844674407u;
932     assert(powmod(x, y, z) == 181227807u);
933     x = 236; y = 7919; z = 1844674407u;
934     assert(powmod(x, y, z) == 217988321u);
935     x = 253; y = 7919; z = 1844674407u;
936     assert(powmod(x, y, z) == 1588843243u);
937 
938     x = 0; y = 7919; z = 184467u;
939     assert(powmod(x, y, z) == 0);
940     x = 123; y = 0; z = 1844674u;
941     assert(powmod(x, y, z) == 1);
942 
943     immutable ubyte x1 = 117;
944     immutable uint y1 = 7919;
945     immutable uint z1 = 1844674407u;
946     auto res = powmod(x1, y1, z1);
947     assert(is(typeof(res) == uint));
948     assert(res == 9479781u);
949 
950     immutable ushort x2 = 123;
951     immutable uint y2 = 203;
952     immutable ubyte z2 = 113;
953     auto res2 = powmod(x2, y2, z2);
954     assert(is(typeof(res2) == ushort));
955     assert(res2 == 42u);
956 }
957 
958 /**
959  * Calculates e$(SUPERSCRIPT x).
960  *
961  *  $(TABLE_SV
962  *    $(TR $(TH x)             $(TH e$(SUPERSCRIPT x)) )
963  *    $(TR $(TD +$(INFIN))     $(TD +$(INFIN)) )
964  *    $(TR $(TD -$(INFIN))     $(TD +0.0)      )
965  *    $(TR $(TD $(NAN))        $(TD $(NAN))    )
966  *  )
967  */
968 pragma(inline, true)
969 real exp(real x) @trusted pure nothrow @nogc // TODO: @safe
970 {
971     version (InlineAsm_X87)
972     {
973         import std.math.constants : LOG2E;
974 
975         //  e^^x = 2^^(LOG2E*x)
976         // (This is valid because the overflow & underflow limits for exp
977         // and exp2 are so similar).
978         if (!__ctfe)
979             return exp2Asm(LOG2E*x);
980     }
981     return expImpl(x);
982 }
983 
984 /// ditto
985 pragma(inline, true)
986 double exp(double x) @safe pure nothrow @nogc { return __ctfe ? cast(double) exp(cast(real) x) : expImpl(x); }
987 
988 /// ditto
989 pragma(inline, true)
990 float exp(float x) @safe pure nothrow @nogc { return __ctfe ? cast(float) exp(cast(real) x) : expImpl(x); }
991 
992 ///
993 @safe unittest
994 {
995     import std.math.operations : feqrel;
996     import std.math.constants : E;
997 
998     assert(exp(0.0) == 1.0);
999     assert(exp(3.0).feqrel(E * E * E) > 16);
1000 }
1001 
1002 private T expImpl(T)(T x) @safe pure nothrow @nogc
1003 {
1004     import std.math : floatTraits, RealFormat;
1005     import std.math.traits : isNaN;
1006     import std.math.rounding : floor;
1007     import std.math.algebraic : poly;
1008     import std.math.constants : LOG2E;
1009 
1010     alias F = floatTraits!T;
1011     static if (F.realFormat == RealFormat.ieeeSingle)
1012     {
1013         static immutable T[6] P = [
1014             5.0000001201E-1,
1015             1.6666665459E-1,
1016             4.1665795894E-2,
1017             8.3334519073E-3,
1018             1.3981999507E-3,
1019             1.9875691500E-4,
1020         ];
1021 
1022         enum T C1 = 0.693359375;
1023         enum T C2 = -2.12194440e-4;
1024 
1025         // Overflow and Underflow limits.
1026         enum T OF = 88.72283905206835;
1027         enum T UF = -103.278929903431851103; // ln(2^-149)
1028     }
1029     else static if (F.realFormat == RealFormat.ieeeDouble)
1030     {
1031         // Coefficients for exp(x)
1032         static immutable T[3] P = [
1033             9.99999999999999999910E-1L,
1034             3.02994407707441961300E-2L,
1035             1.26177193074810590878E-4L,
1036         ];
1037         static immutable T[4] Q = [
1038             2.00000000000000000009E0L,
1039             2.27265548208155028766E-1L,
1040             2.52448340349684104192E-3L,
1041             3.00198505138664455042E-6L,
1042         ];
1043 
1044         // C1 + C2 = LN2.
1045         enum T C1 = 6.93145751953125E-1;
1046         enum T C2 = 1.42860682030941723212E-6;
1047 
1048         // Overflow and Underflow limits.
1049         enum T OF =  7.09782712893383996732E2;  // ln((1-2^-53) * 2^1024)
1050         enum T UF = -7.451332191019412076235E2; // ln(2^-1075)
1051     }
1052     else static if (F.realFormat == RealFormat.ieeeExtended ||
1053                     F.realFormat == RealFormat.ieeeExtended53)
1054     {
1055         // Coefficients for exp(x)
1056         static immutable T[3] P = [
1057             9.9999999999999999991025E-1L,
1058             3.0299440770744196129956E-2L,
1059             1.2617719307481059087798E-4L,
1060         ];
1061         static immutable T[4] Q = [
1062             2.0000000000000000000897E0L,
1063             2.2726554820815502876593E-1L,
1064             2.5244834034968410419224E-3L,
1065             3.0019850513866445504159E-6L,
1066         ];
1067 
1068         // C1 + C2 = LN2.
1069         enum T C1 = 6.9314575195312500000000E-1L;
1070         enum T C2 = 1.4286068203094172321215E-6L;
1071 
1072         // Overflow and Underflow limits.
1073         enum T OF =  1.1356523406294143949492E4L;  // ln((1-2^-64) * 2^16384)
1074         enum T UF = -1.13994985314888605586758E4L; // ln(2^-16446)
1075     }
1076     else static if (F.realFormat == RealFormat.ieeeQuadruple)
1077     {
1078         // Coefficients for exp(x) - 1
1079         static immutable T[5] P = [
1080             9.999999999999999999999999999999999998502E-1L,
1081             3.508710990737834361215404761139478627390E-2L,
1082             2.708775201978218837374512615596512792224E-4L,
1083             6.141506007208645008909088812338454698548E-7L,
1084             3.279723985560247033712687707263393506266E-10L
1085         ];
1086         static immutable T[6] Q = [
1087             2.000000000000000000000000000000000000150E0,
1088             2.368408864814233538909747618894558968880E-1L,
1089             3.611828913847589925056132680618007270344E-3L,
1090             1.504792651814944826817779302637284053660E-5L,
1091             1.771372078166251484503904874657985291164E-8L,
1092             2.980756652081995192255342779918052538681E-12L
1093         ];
1094 
1095         // C1 + C2 = LN2.
1096         enum T C1 = 6.93145751953125E-1L;
1097         enum T C2 = 1.428606820309417232121458176568075500134E-6L;
1098 
1099         // Overflow and Underflow limits.
1100         enum T OF =  1.135583025911358400418251384584930671458833e4L;
1101         enum T UF = -1.143276959615573793352782661133116431383730e4L;
1102     }
1103     else
1104         static assert(0, "Not implemented for this architecture");
1105 
1106     // Special cases.
1107     if (isNaN(x))
1108         return x;
1109     if (x > OF)
1110         return real.infinity;
1111     if (x < UF)
1112         return 0.0;
1113 
1114     // Express: e^^x = e^^g * 2^^n
1115     //   = e^^g * e^^(n * LOG2E)
1116     //   = e^^(g + n * LOG2E)
1117     T xx = floor((cast(T) LOG2E) * x + cast(T) 0.5);
1118     const int n = cast(int) xx;
1119     x -= xx * C1;
1120     x -= xx * C2;
1121 
1122     static if (F.realFormat == RealFormat.ieeeSingle)
1123     {
1124         xx = x * x;
1125         x = poly(x, P) * xx + x + 1.0f;
1126     }
1127     else
1128     {
1129         // Rational approximation for exponential of the fractional part:
1130         //  e^^x = 1 + 2x P(x^^2) / (Q(x^^2) - P(x^^2))
1131         xx = x * x;
1132         const T px = x * poly(xx, P);
1133         x = px / (poly(xx, Q) - px);
1134         x = (cast(T) 1.0) + (cast(T) 2.0) * x;
1135     }
1136 
1137     // Scale by power of 2.
1138     x = core.math.ldexp(x, n);
1139 
1140     return x;
1141 }
1142 
1143 @safe @nogc nothrow unittest
1144 {
1145     import std.math : floatTraits, RealFormat;
1146     import std.math.operations : NaN, feqrel, isClose;
1147     import std.math.constants : E;
1148     import std.math.traits : isIdentical;
1149     import std.math.algebraic : abs;
1150 
1151     version (IeeeFlagsSupport) import std.math.hardware : IeeeFlags, resetIeeeFlags, ieeeFlags;
1152     version (FloatingPointControlSupport)
1153     {
1154         import std.math.hardware : FloatingPointControl;
1155 
1156         FloatingPointControl ctrl;
1157         if (FloatingPointControl.hasExceptionTraps)
1158             ctrl.disableExceptions(FloatingPointControl.allExceptions);
1159         ctrl.rounding = FloatingPointControl.roundToNearest;
1160     }
1161 
1162     static void testExp(T)()
1163     {
1164         enum realFormat = floatTraits!T.realFormat;
1165         static if (realFormat == RealFormat.ieeeQuadruple)
1166         {
1167             static immutable T[2][] exptestpoints =
1168             [ //  x               exp(x)
1169                 [ 1.0L,           E                                        ],
1170                 [ 0.5L,           0x1.a61298e1e069bc972dfefab6df34p+0L     ],
1171                 [ 3.0L,           E*E*E                                    ],
1172                 [ 0x1.6p+13L,     0x1.6e509d45728655cdb4840542acb5p+16250L ], // near overflow
1173                 [ 0x1.7p+13L,     T.infinity                               ], // close overflow
1174                 [ 0x1p+80L,       T.infinity                               ], // far overflow
1175                 [ T.infinity,     T.infinity                               ],
1176                 [-0x1.18p+13L,    0x1.5e4bf54b4807034ea97fef0059a6p-12927L ], // near underflow
1177                 [-0x1.625p+13L,   0x1.a6bd68a39d11fec3a250cd97f524p-16358L ], // ditto
1178                 [-0x1.62dafp+13L, 0x0.cb629e9813b80ed4d639e875be6cp-16382L ], // near underflow - subnormal
1179                 [-0x1.6549p+13L,  0x0.0000000000000000000000000001p-16382L ], // ditto
1180                 [-0x1.655p+13L,   0                                        ], // close underflow
1181                 [-0x1p+30L,       0                                        ], // far underflow
1182             ];
1183         }
1184         else static if (realFormat == RealFormat.ieeeExtended ||
1185                         realFormat == RealFormat.ieeeExtended53)
1186         {
1187             static immutable T[2][] exptestpoints =
1188             [ //  x               exp(x)
1189                 [ 1.0L,           E                            ],
1190                 [ 0.5L,           0x1.a61298e1e069bc97p+0L     ],
1191                 [ 3.0L,           E*E*E                        ],
1192                 [ 0x1.1p+13L,     0x1.29aeffefc8ec645p+12557L  ], // near overflow
1193                 [ 0x1.7p+13L,     T.infinity                   ], // close overflow
1194                 [ 0x1p+80L,       T.infinity                   ], // far overflow
1195                 [ T.infinity,     T.infinity                   ],
1196                 [-0x1.18p+13L,    0x1.5e4bf54b4806db9p-12927L  ], // near underflow
1197                 [-0x1.625p+13L,   0x1.a6bd68a39d11f35cp-16358L ], // ditto
1198                 [-0x1.62dafp+13L, 0x1.96c53d30277021dp-16383L  ], // near underflow - subnormal
1199                 [-0x1.643p+13L,   0x1p-16444L                  ], // ditto
1200                 [-0x1.645p+13L,   0                            ], // close underflow
1201                 [-0x1p+30L,       0                            ], // far underflow
1202             ];
1203         }
1204         else static if (realFormat == RealFormat.ieeeDouble)
1205         {
1206             static immutable T[2][] exptestpoints =
1207             [ //  x,             exp(x)
1208                 [ 1.0L,          E                        ],
1209                 [ 0.5L,          0x1.a61298e1e069cp+0L    ],
1210                 [ 3.0L,          E*E*E                    ],
1211                 [ 0x1.6p+9L,     0x1.93bf4ec282efbp+1015L ], // near overflow
1212                 [ 0x1.7p+9L,     T.infinity               ], // close overflow
1213                 [ 0x1p+80L,      T.infinity               ], // far overflow
1214                 [ T.infinity,    T.infinity               ],
1215                 [-0x1.6p+9L,     0x1.44a3824e5285fp-1016L ], // near underflow
1216                 [-0x1.64p+9L,    0x0.06f84920bb2d4p-1022L ], // near underflow - subnormal
1217                 [-0x1.743p+9L,   0x0.0000000000001p-1022L ], // ditto
1218                 [-0x1.8p+9L,     0                        ], // close underflow
1219                 [-0x1p+30L,      0                        ], // far underflow
1220             ];
1221         }
1222         else static if (realFormat == RealFormat.ieeeSingle)
1223         {
1224             static immutable T[2][] exptestpoints =
1225             [ //  x,             exp(x)
1226                 [ 1.0L,          E                ],
1227                 [ 0.5L,          0x1.a61299p+0L   ],
1228                 [ 3.0L,          E*E*E            ],
1229                 [ 0x1.62p+6L,    0x1.99b988p+127L ], // near overflow
1230                 [ 0x1.7p+6L,     T.infinity       ], // close overflow
1231                 [ 0x1p+80L,      T.infinity       ], // far overflow
1232                 [ T.infinity,    T.infinity       ],
1233                 [-0x1.5cp+6L,    0x1.666d0ep-126L ], // near underflow
1234                 [-0x1.7p+6L,     0x0.026a42p-126L ], // near underflow - subnormal
1235                 [-0x1.9cp+6L,    0x0.000002p-126L ], // ditto
1236                 [-0x1.ap+6L,     0                ], // close underflow
1237                 [-0x1p+30L,      0                ], // far underflow
1238             ];
1239         }
1240         else
1241             static assert(0, "No exp() tests for real type!");
1242 
1243         const minEqualMantissaBits = T.mant_dig - 2;
1244         T x;
1245         version (IeeeFlagsSupport) IeeeFlags f;
1246         foreach (ref pair; exptestpoints)
1247         {
1248             version (IeeeFlagsSupport) resetIeeeFlags();
1249             x = exp(pair[0]);
1250             //printf("exp(%La) = %La, should be %La\n", cast(real) pair[0], cast(real) x, cast(real) pair[1]);
1251             assert(feqrel(x, pair[1]) >= minEqualMantissaBits);
1252         }
1253 
1254         // Ideally, exp(0) would not set the inexact flag.
1255         // Unfortunately, fldl2e sets it!
1256         // So it's not realistic to avoid setting it.
1257         assert(exp(cast(T) 0.0) == 1.0);
1258 
1259         // NaN propagation. Doesn't set flags, bcos was already NaN.
1260         version (IeeeFlagsSupport)
1261         {
1262             resetIeeeFlags();
1263             x = exp(T.nan);
1264             f = ieeeFlags;
1265             assert(isIdentical(abs(x), T.nan));
1266             assert(f.flags == 0);
1267 
1268             resetIeeeFlags();
1269             x = exp(-T.nan);
1270             f = ieeeFlags;
1271             assert(isIdentical(abs(x), T.nan));
1272             assert(f.flags == 0);
1273         }
1274         else
1275         {
1276             x = exp(T.nan);
1277             assert(isIdentical(abs(x), T.nan));
1278 
1279             x = exp(-T.nan);
1280             assert(isIdentical(abs(x), T.nan));
1281         }
1282 
1283         x = exp(NaN(0x123));
1284         assert(isIdentical(x, NaN(0x123)));
1285     }
1286 
1287     import std.meta : AliasSeq;
1288     foreach (T; AliasSeq!(real, double, float))
1289         testExp!T();
1290 
1291     // High resolution test (verified against GNU MPFR/Mathematica).
1292     assert(exp(0.5L) == 0x1.A612_98E1_E069_BC97_2DFE_FAB6_DF34p+0L);
1293 
1294     assert(isClose(exp(3.0L), E * E * E, real.sizeof > double.sizeof ? 1e-15 : 1e-14));
1295 }
1296 
1297 /**
1298  * Calculates the value of the natural logarithm base (e)
1299  * raised to the power of x, minus 1.
1300  *
1301  * For very small x, expm1(x) is more accurate
1302  * than exp(x)-1.
1303  *
1304  *  $(TABLE_SV
1305  *    $(TR $(TH x)             $(TH e$(SUPERSCRIPT x)-1)  )
1306  *    $(TR $(TD $(PLUSMN)0.0)  $(TD $(PLUSMN)0.0) )
1307  *    $(TR $(TD +$(INFIN))     $(TD +$(INFIN))    )
1308  *    $(TR $(TD -$(INFIN))     $(TD -1.0)         )
1309  *    $(TR $(TD $(NAN))        $(TD $(NAN))       )
1310  *  )
1311  */
1312 pragma(inline, true)
1313 real expm1(real x) @trusted pure nothrow @nogc // TODO: @safe
1314 {
1315     version (InlineAsm_X87)
1316     {
1317         if (!__ctfe)
1318             return expm1Asm(x);
1319     }
1320     return expm1Impl(x);
1321 }
1322 
1323 /// ditto
1324 pragma(inline, true)
1325 double expm1(double x) @safe pure nothrow @nogc
1326 {
1327     return __ctfe ? cast(double) expm1(cast(real) x) : expm1Impl(x);
1328 }
1329 
1330 /// ditto
1331 pragma(inline, true)
1332 float expm1(float x) @safe pure nothrow @nogc
1333 {
1334     // no single-precision version in Cephes => use double precision
1335     return __ctfe ? cast(float) expm1(cast(real) x) : cast(float) expm1Impl(cast(double) x);
1336 }
1337 
1338 ///
1339 @safe unittest
1340 {
1341     import std.math.traits : isIdentical;
1342     import std.math.operations : feqrel;
1343 
1344     assert(isIdentical(expm1(0.0), 0.0));
1345     assert(expm1(1.0).feqrel(1.71828) > 16);
1346     assert(expm1(2.0).feqrel(6.3890) > 16);
1347 }
1348 
1349 version (InlineAsm_X87)
1350 private real expm1Asm(real x) @trusted pure nothrow @nogc
1351 {
1352     version (X86)
1353     {
1354         enum PARAMSIZE = (real.sizeof+3)&(0xFFFF_FFFC); // always a multiple of 4
1355         asm pure nothrow @nogc
1356         {
1357             /*  expm1() for x87 80-bit reals, IEEE754-2008 conformant.
1358              * Author: Don Clugston.
1359              *
1360              *    expm1(x) = 2^^(rndint(y))* 2^^(y-rndint(y)) - 1 where y = LN2*x.
1361              *    = 2rndy * 2ym1 + 2rndy - 1, where 2rndy = 2^^(rndint(y))
1362              *     and 2ym1 = (2^^(y-rndint(y))-1).
1363              *    If 2rndy  < 0.5*real.epsilon, result is -1.
1364              *    Implementation is otherwise the same as for exp2()
1365              */
1366             naked;
1367             fld real ptr [ESP+4] ; // x
1368             mov AX, [ESP+4+8]; // AX = exponent and sign
1369             sub ESP, 12+8; // Create scratch space on the stack
1370             // [ESP,ESP+2] = scratchint
1371             // [ESP+4..+6, +8..+10, +10] = scratchreal
1372             // set scratchreal mantissa = 1.0
1373             mov dword ptr [ESP+8], 0;
1374             mov dword ptr [ESP+8+4], 0x80000000;
1375             and AX, 0x7FFF; // drop sign bit
1376             cmp AX, 0x401D; // avoid InvalidException in fist
1377             jae L_extreme;
1378             fldl2e;
1379             fmulp ST(1), ST; // y = x*log2(e)
1380             fist dword ptr [ESP]; // scratchint = rndint(y)
1381             fisub dword ptr [ESP]; // y - rndint(y)
1382             // and now set scratchreal exponent
1383             mov EAX, [ESP];
1384             add EAX, 0x3fff;
1385             jle short L_largenegative;
1386             cmp EAX,0x8000;
1387             jge short L_largepositive;
1388             mov [ESP+8+8],AX;
1389             f2xm1; // 2ym1 = 2^^(y-rndint(y)) -1
1390             fld real ptr [ESP+8] ; // 2rndy = 2^^rndint(y)
1391             fmul ST(1), ST;  // ST=2rndy, ST(1)=2rndy*2ym1
1392             fld1;
1393             fsubp ST(1), ST; // ST = 2rndy-1, ST(1) = 2rndy * 2ym1 - 1
1394             faddp ST(1), ST; // ST = 2rndy * 2ym1 + 2rndy - 1
1395             add ESP,12+8;
1396             ret PARAMSIZE;
1397 
1398 L_extreme:  // Extreme exponent. X is very large positive, very
1399             // large negative, infinity, or NaN.
1400             fxam;
1401             fstsw AX;
1402             test AX, 0x0400; // NaN_or_zero, but we already know x != 0
1403             jz L_was_nan;  // if x is NaN, returns x
1404             test AX, 0x0200;
1405             jnz L_largenegative;
1406 L_largepositive:
1407             // Set scratchreal = real.max.
1408             // squaring it will create infinity, and set overflow flag.
1409             mov word  ptr [ESP+8+8], 0x7FFE;
1410             fstp ST(0);
1411             fld real ptr [ESP+8];  // load scratchreal
1412             fmul ST(0), ST;        // square it, to create havoc!
1413 L_was_nan:
1414             add ESP,12+8;
1415             ret PARAMSIZE;
1416 L_largenegative:
1417             fstp ST(0);
1418             fld1;
1419             fchs; // return -1. Underflow flag is not set.
1420             add ESP,12+8;
1421             ret PARAMSIZE;
1422         }
1423     }
1424     else version (X86_64)
1425     {
1426         asm pure nothrow @nogc
1427         {
1428             naked;
1429         }
1430         version (Win64)
1431         {
1432             asm pure nothrow @nogc
1433             {
1434                 fld   real ptr [RCX];  // x
1435                 mov   AX,[RCX+8];      // AX = exponent and sign
1436             }
1437         }
1438         else
1439         {
1440             asm pure nothrow @nogc
1441             {
1442                 fld   real ptr [RSP+8];  // x
1443                 mov   AX,[RSP+8+8];      // AX = exponent and sign
1444             }
1445         }
1446         asm pure nothrow @nogc
1447         {
1448             /*  expm1() for x87 80-bit reals, IEEE754-2008 conformant.
1449              * Author: Don Clugston.
1450              *
1451              *    expm1(x) = 2^(rndint(y))* 2^(y-rndint(y)) - 1 where y = LN2*x.
1452              *    = 2rndy * 2ym1 + 2rndy - 1, where 2rndy = 2^(rndint(y))
1453              *     and 2ym1 = (2^(y-rndint(y))-1).
1454              *    If 2rndy  < 0.5*real.epsilon, result is -1.
1455              *    Implementation is otherwise the same as for exp2()
1456              */
1457             sub RSP, 24;       // Create scratch space on the stack
1458             // [RSP,RSP+2] = scratchint
1459             // [RSP+4..+6, +8..+10, +10] = scratchreal
1460             // set scratchreal mantissa = 1.0
1461             mov dword ptr [RSP+8], 0;
1462             mov dword ptr [RSP+8+4], 0x80000000;
1463             and AX, 0x7FFF; // drop sign bit
1464             cmp AX, 0x401D; // avoid InvalidException in fist
1465             jae L_extreme;
1466             fldl2e;
1467             fmul ; // y = x*log2(e)
1468             fist dword ptr [RSP]; // scratchint = rndint(y)
1469             fisub dword ptr [RSP]; // y - rndint(y)
1470             // and now set scratchreal exponent
1471             mov EAX, [RSP];
1472             add EAX, 0x3fff;
1473             jle short L_largenegative;
1474             cmp EAX,0x8000;
1475             jge short L_largepositive;
1476             mov [RSP+8+8],AX;
1477             f2xm1; // 2^(y-rndint(y)) -1
1478             fld real ptr [RSP+8] ; // 2^rndint(y)
1479             fmul ST(1), ST;
1480             fld1;
1481             fsubp ST(1), ST;
1482             fadd;
1483             add RSP,24;
1484             ret;
1485 
1486 L_extreme:  // Extreme exponent. X is very large positive, very
1487             // large negative, infinity, or NaN.
1488             fxam;
1489             fstsw AX;
1490             test AX, 0x0400; // NaN_or_zero, but we already know x != 0
1491             jz L_was_nan;  // if x is NaN, returns x
1492             test AX, 0x0200;
1493             jnz L_largenegative;
1494 L_largepositive:
1495             // Set scratchreal = real.max.
1496             // squaring it will create infinity, and set overflow flag.
1497             mov word  ptr [RSP+8+8], 0x7FFE;
1498             fstp ST(0);
1499             fld real ptr [RSP+8];  // load scratchreal
1500             fmul ST(0), ST;        // square it, to create havoc!
1501 L_was_nan:
1502             add RSP,24;
1503             ret;
1504 
1505 L_largenegative:
1506             fstp ST(0);
1507             fld1;
1508             fchs; // return -1. Underflow flag is not set.
1509             add RSP,24;
1510             ret;
1511         }
1512     }
1513     else
1514         static assert(0);
1515 }
1516 
1517 private T expm1Impl(T)(T x) @safe pure nothrow @nogc
1518 {
1519     import std.math : floatTraits, RealFormat;
1520     import std.math.rounding : floor;
1521     import std.math.algebraic : poly;
1522     import std.math.constants : LN2;
1523 
1524     // Coefficients for exp(x) - 1 and overflow/underflow limits.
1525     enum realFormat = floatTraits!T.realFormat;
1526     static if (realFormat == RealFormat.ieeeQuadruple)
1527     {
1528         static immutable T[8] P = [
1529             2.943520915569954073888921213330863757240E8L,
1530             -5.722847283900608941516165725053359168840E7L,
1531             8.944630806357575461578107295909719817253E6L,
1532             -7.212432713558031519943281748462837065308E5L,
1533             4.578962475841642634225390068461943438441E4L,
1534             -1.716772506388927649032068540558788106762E3L,
1535             4.401308817383362136048032038528753151144E1L,
1536             -4.888737542888633647784737721812546636240E-1L
1537         ];
1538 
1539         static immutable T[9] Q = [
1540             1.766112549341972444333352727998584753865E9L,
1541             -7.848989743695296475743081255027098295771E8L,
1542             1.615869009634292424463780387327037251069E8L,
1543             -2.019684072836541751428967854947019415698E7L,
1544             1.682912729190313538934190635536631941751E6L,
1545             -9.615511549171441430850103489315371768998E4L,
1546             3.697714952261803935521187272204485251835E3L,
1547             -8.802340681794263968892934703309274564037E1L,
1548             1.0
1549         ];
1550 
1551         enum T OF = 1.1356523406294143949491931077970764891253E4L;
1552         enum T UF = -1.143276959615573793352782661133116431383730e4L;
1553     }
1554     else static if (realFormat == RealFormat.ieeeExtended)
1555     {
1556         static immutable T[5] P = [
1557            -1.586135578666346600772998894928250240826E4L,
1558             2.642771505685952966904660652518429479531E3L,
1559            -3.423199068835684263987132888286791620673E2L,
1560             1.800826371455042224581246202420972737840E1L,
1561            -5.238523121205561042771939008061958820811E-1L,
1562         ];
1563         static immutable T[6] Q = [
1564            -9.516813471998079611319047060563358064497E4L,
1565             3.964866271411091674556850458227710004570E4L,
1566            -7.207678383830091850230366618190187434796E3L,
1567             7.206038318724600171970199625081491823079E2L,
1568            -4.002027679107076077238836622982900945173E1L,
1569             1.0
1570         ];
1571 
1572         enum T OF =  1.1356523406294143949492E4L;
1573         enum T UF = -4.5054566736396445112120088E1L;
1574     }
1575     else static if (realFormat == RealFormat.ieeeDouble)
1576     {
1577         static immutable T[3] P = [
1578             9.9999999999999999991025E-1,
1579             3.0299440770744196129956E-2,
1580             1.2617719307481059087798E-4,
1581         ];
1582         static immutable T[4] Q = [
1583             2.0000000000000000000897E0,
1584             2.2726554820815502876593E-1,
1585             2.5244834034968410419224E-3,
1586             3.0019850513866445504159E-6,
1587         ];
1588     }
1589     else
1590         static assert(0, "no coefficients for expm1()");
1591 
1592     static if (realFormat == RealFormat.ieeeDouble) // special case for double precision
1593     {
1594         if (x < -0.5 || x > 0.5)
1595             return exp(x) - 1.0;
1596         if (x == 0.0)
1597             return x;
1598 
1599         const T xx = x * x;
1600         x = x * poly(xx, P);
1601         x = x / (poly(xx, Q) - x);
1602         return x + x;
1603     }
1604     else
1605     {
1606         // C1 + C2 = LN2.
1607         enum T C1 = 6.9314575195312500000000E-1L;
1608         enum T C2 = 1.428606820309417232121458176568075500134E-6L;
1609 
1610         // Special cases.
1611         if (x > OF)
1612             return real.infinity;
1613         if (x == cast(T) 0.0)
1614             return x;
1615         if (x < UF)
1616             return -1.0;
1617 
1618         // Express x = LN2 (n + remainder), remainder not exceeding 1/2.
1619         int n = cast(int) floor((cast(T) 0.5) + x / cast(T) LN2);
1620         x -= n * C1;
1621         x -= n * C2;
1622 
1623         // Rational approximation:
1624         //  exp(x) - 1 = x + 0.5 x^^2 + x^^3 P(x) / Q(x)
1625         T px = x * poly(x, P);
1626         T qx = poly(x, Q);
1627         const T xx = x * x;
1628         qx = x + ((cast(T) 0.5) * xx + xx * px / qx);
1629 
1630         // We have qx = exp(remainder LN2) - 1, so:
1631         //  exp(x) - 1 = 2^^n (qx + 1) - 1 = 2^^n qx + 2^^n - 1.
1632         px = core.math.ldexp(cast(T) 1.0, n);
1633         x = px * qx + (px - cast(T) 1.0);
1634 
1635         return x;
1636     }
1637 }
1638 
1639 @safe @nogc nothrow unittest
1640 {
1641     import std.math.traits : isNaN;
1642     import std.math.operations : isClose, CommonDefaultFor;
1643 
1644     static void testExpm1(T)()
1645     {
1646         // NaN
1647         assert(isNaN(expm1(cast(T) T.nan)));
1648 
1649         static immutable T[] xs = [ -2, -0.75, -0.3, 0.0, 0.1, 0.2, 0.5, 1.0 ];
1650         foreach (x; xs)
1651         {
1652             const T e = expm1(x);
1653             const T r = exp(x) - 1;
1654 
1655             //printf("expm1(%Lg) = %Lg, should approximately be %Lg\n", cast(real) x, cast(real) e, cast(real) r);
1656             assert(isClose(r, e, CommonDefaultFor!(T,T), CommonDefaultFor!(T,T)));
1657         }
1658     }
1659 
1660     import std.meta : AliasSeq;
1661     foreach (T; AliasSeq!(real, double))
1662         testExpm1!T();
1663 }
1664 
1665 /**
1666  * Calculates 2$(SUPERSCRIPT x).
1667  *
1668  *  $(TABLE_SV
1669  *    $(TR $(TH x)             $(TH exp2(x))   )
1670  *    $(TR $(TD +$(INFIN))     $(TD +$(INFIN)) )
1671  *    $(TR $(TD -$(INFIN))     $(TD +0.0)      )
1672  *    $(TR $(TD $(NAN))        $(TD $(NAN))    )
1673  *  )
1674  */
1675 pragma(inline, true)
1676 real exp2(real x) @nogc @trusted pure nothrow // TODO: @safe
1677 {
1678     version (InlineAsm_X87)
1679     {
1680         if (!__ctfe)
1681             return exp2Asm(x);
1682     }
1683     return exp2Impl(x);
1684 }
1685 
1686 /// ditto
1687 pragma(inline, true)
1688 double exp2(double x) @nogc @safe pure nothrow { return __ctfe ? cast(double) exp2(cast(real) x) : exp2Impl(x); }
1689 
1690 /// ditto
1691 pragma(inline, true)
1692 float exp2(float x) @nogc @safe pure nothrow { return __ctfe ? cast(float) exp2(cast(real) x) : exp2Impl(x); }
1693 
1694 ///
1695 @safe unittest
1696 {
1697     import std.math.traits : isIdentical;
1698     import std.math.operations : feqrel;
1699 
1700     assert(isIdentical(exp2(0.0), 1.0));
1701     assert(exp2(2.0).feqrel(4.0) > 16);
1702     assert(exp2(8.0).feqrel(256.0) > 16);
1703 }
1704 
1705 @safe unittest
1706 {
1707     version (CRuntime_Microsoft) {} else // aexp2/exp2f/exp2l not implemented
1708     {
1709         assert( core.stdc.math.exp2f(0.0f) == 1 );
1710         assert( core.stdc.math.exp2 (0.0)  == 1 );
1711         assert( core.stdc.math.exp2l(0.0L) == 1 );
1712     }
1713 }
1714 
1715 version (InlineAsm_X87)
1716 private real exp2Asm(real x) @nogc @trusted pure nothrow
1717 {
1718     version (X86)
1719     {
1720         enum PARAMSIZE = (real.sizeof+3)&(0xFFFF_FFFC); // always a multiple of 4
1721 
1722         asm pure nothrow @nogc
1723         {
1724             /*  exp2() for x87 80-bit reals, IEEE754-2008 conformant.
1725              * Author: Don Clugston.
1726              *
1727              * exp2(x) = 2^^(rndint(x))* 2^^(y-rndint(x))
1728              * The trick for high performance is to avoid the fscale(28cycles on core2),
1729              * frndint(19 cycles), leaving f2xm1(19 cycles) as the only slow instruction.
1730              *
1731              * We can do frndint by using fist. BUT we can't use it for huge numbers,
1732              * because it will set the Invalid Operation flag if overflow or NaN occurs.
1733              * Fortunately, whenever this happens the result would be zero or infinity.
1734              *
1735              * We can perform fscale by directly poking into the exponent. BUT this doesn't
1736              * work for the (very rare) cases where the result is subnormal. So we fall back
1737              * to the slow method in that case.
1738              */
1739             naked;
1740             fld real ptr [ESP+4] ; // x
1741             mov AX, [ESP+4+8]; // AX = exponent and sign
1742             sub ESP, 12+8; // Create scratch space on the stack
1743             // [ESP,ESP+2] = scratchint
1744             // [ESP+4..+6, +8..+10, +10] = scratchreal
1745             // set scratchreal mantissa = 1.0
1746             mov dword ptr [ESP+8], 0;
1747             mov dword ptr [ESP+8+4], 0x80000000;
1748             and AX, 0x7FFF; // drop sign bit
1749             cmp AX, 0x401D; // avoid InvalidException in fist
1750             jae L_extreme;
1751             fist dword ptr [ESP]; // scratchint = rndint(x)
1752             fisub dword ptr [ESP]; // x - rndint(x)
1753             // and now set scratchreal exponent
1754             mov EAX, [ESP];
1755             add EAX, 0x3fff;
1756             jle short L_subnormal;
1757             cmp EAX,0x8000;
1758             jge short L_overflow;
1759             mov [ESP+8+8],AX;
1760 L_normal:
1761             f2xm1;
1762             fld1;
1763             faddp ST(1), ST; // 2^^(x-rndint(x))
1764             fld real ptr [ESP+8] ; // 2^^rndint(x)
1765             add ESP,12+8;
1766             fmulp ST(1), ST;
1767             ret PARAMSIZE;
1768 
1769 L_subnormal:
1770             // Result will be subnormal.
1771             // In this rare case, the simple poking method doesn't work.
1772             // The speed doesn't matter, so use the slow fscale method.
1773             fild dword ptr [ESP];  // scratchint
1774             fld1;
1775             fscale;
1776             fstp real ptr [ESP+8]; // scratchreal = 2^^scratchint
1777             fstp ST(0);         // drop scratchint
1778             jmp L_normal;
1779 
1780 L_extreme:  // Extreme exponent. X is very large positive, very
1781             // large negative, infinity, or NaN.
1782             fxam;
1783             fstsw AX;
1784             test AX, 0x0400; // NaN_or_zero, but we already know x != 0
1785             jz L_was_nan;  // if x is NaN, returns x
1786             // set scratchreal = real.min_normal
1787             // squaring it will return 0, setting underflow flag
1788             mov word  ptr [ESP+8+8], 1;
1789             test AX, 0x0200;
1790             jnz L_waslargenegative;
1791 L_overflow:
1792             // Set scratchreal = real.max.
1793             // squaring it will create infinity, and set overflow flag.
1794             mov word  ptr [ESP+8+8], 0x7FFE;
1795 L_waslargenegative:
1796             fstp ST(0);
1797             fld real ptr [ESP+8];  // load scratchreal
1798             fmul ST(0), ST;        // square it, to create havoc!
1799 L_was_nan:
1800             add ESP,12+8;
1801             ret PARAMSIZE;
1802         }
1803     }
1804     else version (X86_64)
1805     {
1806         asm pure nothrow @nogc
1807         {
1808             naked;
1809         }
1810         version (Win64)
1811         {
1812             asm pure nothrow @nogc
1813             {
1814                 fld   real ptr [RCX];  // x
1815                 mov   AX,[RCX+8];      // AX = exponent and sign
1816             }
1817         }
1818         else
1819         {
1820             asm pure nothrow @nogc
1821             {
1822                 fld   real ptr [RSP+8];  // x
1823                 mov   AX,[RSP+8+8];      // AX = exponent and sign
1824             }
1825         }
1826         asm pure nothrow @nogc
1827         {
1828             /*  exp2() for x87 80-bit reals, IEEE754-2008 conformant.
1829              * Author: Don Clugston.
1830              *
1831              * exp2(x) = 2^(rndint(x))* 2^(y-rndint(x))
1832              * The trick for high performance is to avoid the fscale(28cycles on core2),
1833              * frndint(19 cycles), leaving f2xm1(19 cycles) as the only slow instruction.
1834              *
1835              * We can do frndint by using fist. BUT we can't use it for huge numbers,
1836              * because it will set the Invalid Operation flag is overflow or NaN occurs.
1837              * Fortunately, whenever this happens the result would be zero or infinity.
1838              *
1839              * We can perform fscale by directly poking into the exponent. BUT this doesn't
1840              * work for the (very rare) cases where the result is subnormal. So we fall back
1841              * to the slow method in that case.
1842              */
1843             sub RSP, 24; // Create scratch space on the stack
1844             // [RSP,RSP+2] = scratchint
1845             // [RSP+4..+6, +8..+10, +10] = scratchreal
1846             // set scratchreal mantissa = 1.0
1847             mov dword ptr [RSP+8], 0;
1848             mov dword ptr [RSP+8+4], 0x80000000;
1849             and AX, 0x7FFF; // drop sign bit
1850             cmp AX, 0x401D; // avoid InvalidException in fist
1851             jae L_extreme;
1852             fist dword ptr [RSP]; // scratchint = rndint(x)
1853             fisub dword ptr [RSP]; // x - rndint(x)
1854             // and now set scratchreal exponent
1855             mov EAX, [RSP];
1856             add EAX, 0x3fff;
1857             jle short L_subnormal;
1858             cmp EAX,0x8000;
1859             jge short L_overflow;
1860             mov [RSP+8+8],AX;
1861 L_normal:
1862             f2xm1;
1863             fld1;
1864             fadd; // 2^(x-rndint(x))
1865             fld real ptr [RSP+8] ; // 2^rndint(x)
1866             add RSP,24;
1867             fmulp ST(1), ST;
1868             ret;
1869 
1870 L_subnormal:
1871             // Result will be subnormal.
1872             // In this rare case, the simple poking method doesn't work.
1873             // The speed doesn't matter, so use the slow fscale method.
1874             fild dword ptr [RSP];  // scratchint
1875             fld1;
1876             fscale;
1877             fstp real ptr [RSP+8]; // scratchreal = 2^scratchint
1878             fstp ST(0);         // drop scratchint
1879             jmp L_normal;
1880 
1881 L_extreme:  // Extreme exponent. X is very large positive, very
1882             // large negative, infinity, or NaN.
1883             fxam;
1884             fstsw AX;
1885             test AX, 0x0400; // NaN_or_zero, but we already know x != 0
1886             jz L_was_nan;  // if x is NaN, returns x
1887             // set scratchreal = real.min
1888             // squaring it will return 0, setting underflow flag
1889             mov word  ptr [RSP+8+8], 1;
1890             test AX, 0x0200;
1891             jnz L_waslargenegative;
1892 L_overflow:
1893             // Set scratchreal = real.max.
1894             // squaring it will create infinity, and set overflow flag.
1895             mov word  ptr [RSP+8+8], 0x7FFE;
1896 L_waslargenegative:
1897             fstp ST(0);
1898             fld real ptr [RSP+8];  // load scratchreal
1899             fmul ST(0), ST;        // square it, to create havoc!
1900 L_was_nan:
1901             add RSP,24;
1902             ret;
1903         }
1904     }
1905     else
1906         static assert(0);
1907 }
1908 
1909 private T exp2Impl(T)(T x) @nogc @safe pure nothrow
1910 {
1911     import std.math : floatTraits, RealFormat;
1912     import std.math.traits : isNaN;
1913     import std.math.rounding : floor;
1914     import std.math.algebraic : poly;
1915 
1916     // Coefficients for exp2(x)
1917     enum realFormat = floatTraits!T.realFormat;
1918     static if (realFormat == RealFormat.ieeeQuadruple)
1919     {
1920         static immutable T[5] P = [
1921             9.079594442980146270952372234833529694788E12L,
1922             1.530625323728429161131811299626419117557E11L,
1923             5.677513871931844661829755443994214173883E8L,
1924             6.185032670011643762127954396427045467506E5L,
1925             1.587171580015525194694938306936721666031E2L
1926         ];
1927 
1928         static immutable T[6] Q = [
1929             2.619817175234089411411070339065679229869E13L,
1930             1.490560994263653042761789432690793026977E12L,
1931             1.092141473886177435056423606755843616331E10L,
1932             2.186249607051644894762167991800811827835E7L,
1933             1.236602014442099053716561665053645270207E4L,
1934             1.0
1935         ];
1936     }
1937     else static if (realFormat == RealFormat.ieeeExtended)
1938     {
1939         static immutable T[3] P = [
1940             2.0803843631901852422887E6L,
1941             3.0286971917562792508623E4L,
1942             6.0614853552242266094567E1L,
1943         ];
1944         static immutable T[4] Q = [
1945             6.0027204078348487957118E6L,
1946             3.2772515434906797273099E5L,
1947             1.7492876999891839021063E3L,
1948             1.0000000000000000000000E0L,
1949         ];
1950     }
1951     else static if (realFormat == RealFormat.ieeeDouble)
1952     {
1953         static immutable T[3] P = [
1954             1.51390680115615096133E3L,
1955             2.02020656693165307700E1L,
1956             2.30933477057345225087E-2L,
1957         ];
1958         static immutable T[3] Q = [
1959             4.36821166879210612817E3L,
1960             2.33184211722314911771E2L,
1961             1.00000000000000000000E0L,
1962         ];
1963     }
1964     else static if (realFormat == RealFormat.ieeeSingle)
1965     {
1966         static immutable T[6] P = [
1967             6.931472028550421E-001L,
1968             2.402264791363012E-001L,
1969             5.550332471162809E-002L,
1970             9.618437357674640E-003L,
1971             1.339887440266574E-003L,
1972             1.535336188319500E-004L,
1973         ];
1974     }
1975     else
1976         static assert(0, "no coefficients for exp2()");
1977 
1978     // Overflow and Underflow limits.
1979     enum T OF = T.max_exp;
1980     enum T UF = T.min_exp - 1;
1981 
1982     // Special cases.
1983     if (isNaN(x))
1984         return x;
1985     if (x > OF)
1986         return real.infinity;
1987     if (x < UF)
1988         return 0.0;
1989 
1990     static if (realFormat == RealFormat.ieeeSingle) // special case for single precision
1991     {
1992         // The following is necessary because range reduction blows up.
1993         if (x == 0.0f)
1994             return 1.0f;
1995 
1996         // Separate into integer and fractional parts.
1997         const T i = floor(x);
1998         int n = cast(int) i;
1999         x -= i;
2000         if (x > 0.5f)
2001         {
2002             n += 1;
2003             x -= 1.0f;
2004         }
2005 
2006         // Rational approximation:
2007         //  exp2(x) = 1.0 + x P(x)
2008         x = 1.0f + x * poly(x, P);
2009     }
2010     else
2011     {
2012         // Separate into integer and fractional parts.
2013         const T i = floor(x + cast(T) 0.5);
2014         int n = cast(int) i;
2015         x -= i;
2016 
2017         // Rational approximation:
2018         //  exp2(x) = 1.0 + 2x P(x^^2) / (Q(x^^2) - P(x^^2))
2019         const T xx = x * x;
2020         const T px = x * poly(xx, P);
2021         x = px / (poly(xx, Q) - px);
2022         x = (cast(T) 1.0) + (cast(T) 2.0) * x;
2023     }
2024 
2025     // Scale by power of 2.
2026     x = core.math.ldexp(x, n);
2027 
2028     return x;
2029 }
2030 
2031 @safe @nogc nothrow unittest
2032 {
2033     import std.math.operations : feqrel, NaN, isClose;
2034     import std.math.traits : isIdentical;
2035     import std.math.constants : SQRT2;
2036 
2037     assert(feqrel(exp2(0.5L), SQRT2) >= real.mant_dig -1);
2038     assert(exp2(8.0L) == 256.0);
2039     assert(exp2(-9.0L)== 1.0L/512.0);
2040 
2041     static void testExp2(T)()
2042     {
2043         // NaN
2044         const T specialNaN = NaN(0x0123L);
2045         assert(isIdentical(exp2(specialNaN), specialNaN));
2046 
2047         // over-/underflow
2048         enum T OF = T.max_exp;
2049         enum T UF = T.min_exp - T.mant_dig;
2050         assert(isIdentical(exp2(OF + 1), cast(T) T.infinity));
2051         assert(isIdentical(exp2(UF - 1), cast(T) 0.0));
2052 
2053         static immutable T[2][] vals =
2054         [
2055             // x, exp2(x)
2056             [  0.0, 1.0 ],
2057             [ -0.0, 1.0 ],
2058             [  0.5, SQRT2 ],
2059             [  8.0, 256.0 ],
2060             [ -9.0, 1.0 / 512 ],
2061         ];
2062 
2063         foreach (ref val; vals)
2064         {
2065             const T x = val[0];
2066             const T r = val[1];
2067             const T e = exp2(x);
2068 
2069             //printf("exp2(%Lg) = %Lg, should be %Lg\n", cast(real) x, cast(real) e, cast(real) r);
2070             assert(isClose(r, e));
2071         }
2072     }
2073 
2074     import std.meta : AliasSeq;
2075     foreach (T; AliasSeq!(real, double, float))
2076         testExp2!T();
2077 }
2078 
2079 /*********************************************************************
2080  * Separate floating point value into significand and exponent.
2081  *
2082  * Returns:
2083  *      Calculate and return $(I x) and $(I exp) such that
2084  *      value =$(I x)*2$(SUPERSCRIPT exp) and
2085  *      .5 $(LT)= |$(I x)| $(LT) 1.0
2086  *
2087  *      $(I x) has same sign as value.
2088  *
2089  *      $(TABLE_SV
2090  *      $(TR $(TH value)           $(TH returns)         $(TH exp))
2091  *      $(TR $(TD $(PLUSMN)0.0)    $(TD $(PLUSMN)0.0)    $(TD 0))
2092  *      $(TR $(TD +$(INFIN))       $(TD +$(INFIN))       $(TD int.max))
2093  *      $(TR $(TD -$(INFIN))       $(TD -$(INFIN))       $(TD int.min))
2094  *      $(TR $(TD $(PLUSMN)$(NAN)) $(TD $(PLUSMN)$(NAN)) $(TD int.min))
2095  *      )
2096  */
2097 T frexp(T)(const T value, out int exp) @trusted pure nothrow @nogc
2098 if (isFloatingPoint!T)
2099 {
2100     import std.math : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB;
2101     import std.math.traits : isSubnormal;
2102 
2103     if (__ctfe)
2104     {
2105         // Handle special cases.
2106         if (value == 0) { exp = 0; return value; }
2107         if (value == T.infinity) { exp = int.max; return value; }
2108         if (value == -T.infinity || value != value) { exp = int.min; return value; }
2109         // Handle ordinary cases.
2110         // In CTFE there is no performance advantage for having separate
2111         // paths for different floating point types.
2112         T absValue = value < 0 ? -value : value;
2113         int expCount;
2114         static if (T.mant_dig > double.mant_dig)
2115         {
2116             for (; absValue >= 0x1.0p+1024L; absValue *= 0x1.0p-1024L)
2117                 expCount += 1024;
2118             for (; absValue < 0x1.0p-1021L; absValue *= 0x1.0p+1021L)
2119                 expCount -= 1021;
2120         }
2121         const double dval = cast(double) absValue;
2122         int dexp = cast(int) (((*cast(const long*) &dval) >>> 52) & 0x7FF) + double.min_exp - 2;
2123         dexp++;
2124         expCount += dexp;
2125         absValue *= 2.0 ^^ -dexp;
2126         // If the original value was subnormal or if it was a real
2127         // then absValue can still be outside the [0.5, 1.0) range.
2128         if (absValue < 0.5)
2129         {
2130             assert(T.mant_dig > double.mant_dig || isSubnormal(value));
2131             do
2132             {
2133                 absValue += absValue;
2134                 expCount--;
2135             } while (absValue < 0.5);
2136         }
2137         else
2138         {
2139             assert(absValue < 1 || T.mant_dig > double.mant_dig);
2140             for (; absValue >= 1; absValue *= T(0.5))
2141                 expCount++;
2142         }
2143         exp = expCount;
2144         return value < 0 ? -absValue : absValue;
2145     }
2146 
2147     Unqual!T vf = value;
2148     ushort* vu = cast(ushort*)&vf;
2149     static if (is(immutable T == immutable float))
2150         int* vi = cast(int*)&vf;
2151     else
2152         long* vl = cast(long*)&vf;
2153     int ex;
2154     alias F = floatTraits!T;
2155 
2156     ex = vu[F.EXPPOS_SHORT] & F.EXPMASK;
2157     static if (F.realFormat == RealFormat.ieeeExtended ||
2158                F.realFormat == RealFormat.ieeeExtended53)
2159     {
2160         if (ex)
2161         {   // If exponent is non-zero
2162             if (ex == F.EXPMASK) // infinity or NaN
2163             {
2164                 if (*vl &  0x7FFF_FFFF_FFFF_FFFF)  // NaN
2165                 {
2166                     *vl |= 0xC000_0000_0000_0000;  // convert NaNS to NaNQ
2167                     exp = int.min;
2168                 }
2169                 else if (vu[F.EXPPOS_SHORT] & 0x8000)   // negative infinity
2170                     exp = int.min;
2171                 else   // positive infinity
2172                     exp = int.max;
2173 
2174             }
2175             else
2176             {
2177                 exp = ex - F.EXPBIAS;
2178                 vu[F.EXPPOS_SHORT] = (0x8000 & vu[F.EXPPOS_SHORT]) | 0x3FFE;
2179             }
2180         }
2181         else if (!*vl)
2182         {
2183             // vf is +-0.0
2184             exp = 0;
2185         }
2186         else
2187         {
2188             // subnormal
2189 
2190             vf *= F.RECIP_EPSILON;
2191             ex = vu[F.EXPPOS_SHORT] & F.EXPMASK;
2192             exp = ex - F.EXPBIAS - T.mant_dig + 1;
2193             vu[F.EXPPOS_SHORT] = ((-1 - F.EXPMASK) & vu[F.EXPPOS_SHORT]) | 0x3FFE;
2194         }
2195         return vf;
2196     }
2197     else static if (F.realFormat == RealFormat.ieeeQuadruple)
2198     {
2199         if (ex)     // If exponent is non-zero
2200         {
2201             if (ex == F.EXPMASK)
2202             {
2203                 // infinity or NaN
2204                 if (vl[MANTISSA_LSB] |
2205                     (vl[MANTISSA_MSB] & 0x0000_FFFF_FFFF_FFFF))  // NaN
2206                 {
2207                     // convert NaNS to NaNQ
2208                     vl[MANTISSA_MSB] |= 0x0000_8000_0000_0000;
2209                     exp = int.min;
2210                 }
2211                 else if (vu[F.EXPPOS_SHORT] & 0x8000)   // negative infinity
2212                     exp = int.min;
2213                 else   // positive infinity
2214                     exp = int.max;
2215             }
2216             else
2217             {
2218                 exp = ex - F.EXPBIAS;
2219                 vu[F.EXPPOS_SHORT] = F.EXPBIAS | (0x8000 & vu[F.EXPPOS_SHORT]);
2220             }
2221         }
2222         else if ((vl[MANTISSA_LSB] |
2223             (vl[MANTISSA_MSB] & 0x0000_FFFF_FFFF_FFFF)) == 0)
2224         {
2225             // vf is +-0.0
2226             exp = 0;
2227         }
2228         else
2229         {
2230             // subnormal
2231             vf *= F.RECIP_EPSILON;
2232             ex = vu[F.EXPPOS_SHORT] & F.EXPMASK;
2233             exp = ex - F.EXPBIAS - T.mant_dig + 1;
2234             vu[F.EXPPOS_SHORT] = F.EXPBIAS | (0x8000 & vu[F.EXPPOS_SHORT]);
2235         }
2236         return vf;
2237     }
2238     else static if (F.realFormat == RealFormat.ieeeDouble)
2239     {
2240         if (ex) // If exponent is non-zero
2241         {
2242             if (ex == F.EXPMASK)   // infinity or NaN
2243             {
2244                 if (*vl == 0x7FF0_0000_0000_0000)  // positive infinity
2245                 {
2246                     exp = int.max;
2247                 }
2248                 else if (*vl == 0xFFF0_0000_0000_0000) // negative infinity
2249                     exp = int.min;
2250                 else
2251                 { // NaN
2252                     *vl |= 0x0008_0000_0000_0000;  // convert NaNS to NaNQ
2253                     exp = int.min;
2254                 }
2255             }
2256             else
2257             {
2258                 exp = (ex - F.EXPBIAS) >> 4;
2259                 vu[F.EXPPOS_SHORT] = cast(ushort)((0x800F & vu[F.EXPPOS_SHORT]) | 0x3FE0);
2260             }
2261         }
2262         else if (!(*vl & 0x7FFF_FFFF_FFFF_FFFF))
2263         {
2264             // vf is +-0.0
2265             exp = 0;
2266         }
2267         else
2268         {
2269             // subnormal
2270             vf *= F.RECIP_EPSILON;
2271             ex = vu[F.EXPPOS_SHORT] & F.EXPMASK;
2272             exp = ((ex - F.EXPBIAS) >> 4) - T.mant_dig + 1;
2273             vu[F.EXPPOS_SHORT] =
2274                 cast(ushort)(((-1 - F.EXPMASK) & vu[F.EXPPOS_SHORT]) | 0x3FE0);
2275         }
2276         return vf;
2277     }
2278     else static if (F.realFormat == RealFormat.ieeeSingle)
2279     {
2280         if (ex) // If exponent is non-zero
2281         {
2282             if (ex == F.EXPMASK)   // infinity or NaN
2283             {
2284                 if (*vi == 0x7F80_0000)  // positive infinity
2285                 {
2286                     exp = int.max;
2287                 }
2288                 else if (*vi == 0xFF80_0000) // negative infinity
2289                     exp = int.min;
2290                 else
2291                 { // NaN
2292                     *vi |= 0x0040_0000;  // convert NaNS to NaNQ
2293                     exp = int.min;
2294                 }
2295             }
2296             else
2297             {
2298                 exp = (ex - F.EXPBIAS) >> 7;
2299                 vu[F.EXPPOS_SHORT] = cast(ushort)((0x807F & vu[F.EXPPOS_SHORT]) | 0x3F00);
2300             }
2301         }
2302         else if (!(*vi & 0x7FFF_FFFF))
2303         {
2304             // vf is +-0.0
2305             exp = 0;
2306         }
2307         else
2308         {
2309             // subnormal
2310             vf *= F.RECIP_EPSILON;
2311             ex = vu[F.EXPPOS_SHORT] & F.EXPMASK;
2312             exp = ((ex - F.EXPBIAS) >> 7) - T.mant_dig + 1;
2313             vu[F.EXPPOS_SHORT] =
2314                 cast(ushort)(((-1 - F.EXPMASK) & vu[F.EXPPOS_SHORT]) | 0x3F00);
2315         }
2316         return vf;
2317     }
2318     else // static if (F.realFormat == RealFormat.ibmExtended)
2319     {
2320         assert(0, "frexp not implemented");
2321     }
2322 }
2323 
2324 ///
2325 @safe unittest
2326 {
2327     import std.math.operations : isClose;
2328 
2329     int exp;
2330     real mantissa = frexp(123.456L, exp);
2331 
2332     assert(isClose(mantissa * pow(2.0L, cast(real) exp), 123.456L));
2333 
2334     assert(frexp(-real.nan, exp) && exp == int.min);
2335     assert(frexp(real.nan, exp) && exp == int.min);
2336     assert(frexp(-real.infinity, exp) == -real.infinity && exp == int.min);
2337     assert(frexp(real.infinity, exp) == real.infinity && exp == int.max);
2338     assert(frexp(-0.0, exp) == -0.0 && exp == 0);
2339     assert(frexp(0.0, exp) == 0.0 && exp == 0);
2340 }
2341 
2342 @safe @nogc nothrow unittest
2343 {
2344     import std.math.operations : isClose;
2345 
2346     int exp;
2347     real mantissa = frexp(123.456L, exp);
2348 
2349     // check if values are equal to 19 decimal digits of precision
2350     assert(isClose(mantissa * pow(2.0L, cast(real) exp), 123.456L, 1e-18));
2351 }
2352 
2353 @safe unittest
2354 {
2355     import std.math : floatTraits, RealFormat;
2356     import std.math.traits : isIdentical;
2357     import std.meta : AliasSeq;
2358     import std.typecons : tuple, Tuple;
2359 
2360     static foreach (T; AliasSeq!(real, double, float))
2361     {{
2362         Tuple!(T, T, int)[] vals = [   // x,frexp,exp
2363             tuple(T(0.0),  T( 0.0 ), 0),
2364             tuple(T(-0.0), T( -0.0), 0),
2365             tuple(T(1.0),  T( .5  ), 1),
2366             tuple(T(-1.0), T( -.5 ), 1),
2367             tuple(T(2.0),  T( .5  ), 2),
2368             tuple(T(float.min_normal/2.0f), T(.5), -126),
2369             tuple(T.infinity, T.infinity, int.max),
2370             tuple(-T.infinity, -T.infinity, int.min),
2371             tuple(T.nan, T.nan, int.min),
2372             tuple(-T.nan, -T.nan, int.min),
2373 
2374             // https://issues.dlang.org/show_bug.cgi?id=16026:
2375             tuple(3 * (T.min_normal * T.epsilon), T( .75), (T.min_exp - T.mant_dig) + 2)
2376         ];
2377 
2378         foreach (elem; vals)
2379         {
2380             T x = elem[0];
2381             T e = elem[1];
2382             int exp = elem[2];
2383             int eptr;
2384             T v = frexp(x, eptr);
2385             assert(isIdentical(e, v));
2386             assert(exp == eptr);
2387         }
2388 
2389         static if (floatTraits!(T).realFormat == RealFormat.ieeeExtended)
2390         {
2391             static T[3][] extendedvals = [ // x,frexp,exp
2392                 [0x1.a5f1c2eb3fe4efp+73L,    0x1.A5F1C2EB3FE4EFp-1L,     74],    // normal
2393                 [0x1.fa01712e8f0471ap-1064L, 0x1.fa01712e8f0471ap-1L, -1063],
2394                 [T.min_normal,      .5, -16381],
2395                 [T.min_normal/2.0L, .5, -16382]    // subnormal
2396             ];
2397             foreach (elem; extendedvals)
2398             {
2399                 T x = elem[0];
2400                 T e = elem[1];
2401                 int exp = cast(int) elem[2];
2402                 int eptr;
2403                 T v = frexp(x, eptr);
2404                 assert(isIdentical(e, v));
2405                 assert(exp == eptr);
2406             }
2407         }
2408     }}
2409 
2410     // CTFE
2411     alias CtfeFrexpResult= Tuple!(real, int);
2412     static CtfeFrexpResult ctfeFrexp(T)(const T value)
2413     {
2414         int exp;
2415         auto significand = frexp(value, exp);
2416         return CtfeFrexpResult(significand, exp);
2417     }
2418     static foreach (T; AliasSeq!(real, double, float))
2419     {{
2420         enum Tuple!(T, T, int)[] vals = [   // x,frexp,exp
2421             tuple(T(0.0),  T( 0.0 ), 0),
2422             tuple(T(-0.0), T( -0.0), 0),
2423             tuple(T(1.0),  T( .5  ), 1),
2424             tuple(T(-1.0), T( -.5 ), 1),
2425             tuple(T(2.0),  T( .5  ), 2),
2426             tuple(T(float.min_normal/2.0f), T(.5), -126),
2427             tuple(T.infinity, T.infinity, int.max),
2428             tuple(-T.infinity, -T.infinity, int.min),
2429             tuple(T.nan, T.nan, int.min),
2430             tuple(-T.nan, -T.nan, int.min),
2431 
2432             // https://issues.dlang.org/show_bug.cgi?id=16026:
2433             tuple(3 * (T.min_normal * T.epsilon), T( .75), (T.min_exp - T.mant_dig) + 2)
2434         ];
2435 
2436         static foreach (elem; vals)
2437         {
2438             static assert(ctfeFrexp(elem[0]) is CtfeFrexpResult(elem[1], elem[2]));
2439         }
2440 
2441         static if (floatTraits!(T).realFormat == RealFormat.ieeeExtended)
2442         {
2443             enum T[3][] extendedvals = [ // x,frexp,exp
2444                 [0x1.a5f1c2eb3fe4efp+73L,    0x1.A5F1C2EB3FE4EFp-1L,     74],    // normal
2445                 [0x1.fa01712e8f0471ap-1064L, 0x1.fa01712e8f0471ap-1L, -1063],
2446                 [T.min_normal,      .5, -16381],
2447                 [T.min_normal/2.0L, .5, -16382]    // subnormal
2448             ];
2449             static foreach (elem; extendedvals)
2450             {
2451                 static assert(ctfeFrexp(elem[0]) is CtfeFrexpResult(elem[1], cast(int) elem[2]));
2452             }
2453         }
2454     }}
2455 }
2456 
2457 @safe unittest
2458 {
2459     import std.meta : AliasSeq;
2460     void foo() {
2461         static foreach (T; AliasSeq!(real, double, float))
2462         {{
2463             int exp;
2464             const T a = 1;
2465             immutable T b = 2;
2466             auto c = frexp(a, exp);
2467             auto d = frexp(b, exp);
2468         }}
2469     }
2470 }
2471 
2472 /******************************************
2473  * Extracts the exponent of x as a signed integral value.
2474  *
2475  * If x is not a special value, the result is the same as
2476  * $(D cast(int) logb(x)).
2477  *
2478  *      $(TABLE_SV
2479  *      $(TR $(TH x)                $(TH ilogb(x))     $(TH Range error?))
2480  *      $(TR $(TD 0)                 $(TD FP_ILOGB0)   $(TD yes))
2481  *      $(TR $(TD $(PLUSMN)$(INFIN)) $(TD int.max)     $(TD no))
2482  *      $(TR $(TD $(NAN))            $(TD FP_ILOGBNAN) $(TD no))
2483  *      )
2484  */
2485 int ilogb(T)(const T x) @trusted pure nothrow @nogc
2486 if (isFloatingPoint!T)
2487 {
2488     import std.math : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB;
2489 
2490     import core.bitop : bsr;
2491     alias F = floatTraits!T;
2492 
2493     union floatBits
2494     {
2495         T rv;
2496         ushort[T.sizeof/2] vu;
2497         uint[T.sizeof/4] vui;
2498         static if (T.sizeof >= 8)
2499             ulong[T.sizeof/8] vul;
2500     }
2501     floatBits y = void;
2502     y.rv = x;
2503 
2504     int ex = y.vu[F.EXPPOS_SHORT] & F.EXPMASK;
2505     static if (F.realFormat == RealFormat.ieeeExtended ||
2506                F.realFormat == RealFormat.ieeeExtended53)
2507     {
2508         if (ex)
2509         {
2510             // If exponent is non-zero
2511             if (ex == F.EXPMASK) // infinity or NaN
2512             {
2513                 if (y.vul[0] &  0x7FFF_FFFF_FFFF_FFFF)  // NaN
2514                     return FP_ILOGBNAN;
2515                 else // +-infinity
2516                     return int.max;
2517             }
2518             else
2519             {
2520                 return ex - F.EXPBIAS - 1;
2521             }
2522         }
2523         else if (!y.vul[0])
2524         {
2525             // vf is +-0.0
2526             return FP_ILOGB0;
2527         }
2528         else
2529         {
2530             // subnormal
2531             return ex - F.EXPBIAS - T.mant_dig + 1 + bsr(y.vul[0]);
2532         }
2533     }
2534     else static if (F.realFormat == RealFormat.ieeeQuadruple)
2535     {
2536         if (ex)    // If exponent is non-zero
2537         {
2538             if (ex == F.EXPMASK)
2539             {
2540                 // infinity or NaN
2541                 if (y.vul[MANTISSA_LSB] | ( y.vul[MANTISSA_MSB] & 0x0000_FFFF_FFFF_FFFF))  // NaN
2542                     return FP_ILOGBNAN;
2543                 else // +- infinity
2544                     return int.max;
2545             }
2546             else
2547             {
2548                 return ex - F.EXPBIAS - 1;
2549             }
2550         }
2551         else if ((y.vul[MANTISSA_LSB] | (y.vul[MANTISSA_MSB] & 0x0000_FFFF_FFFF_FFFF)) == 0)
2552         {
2553             // vf is +-0.0
2554             return FP_ILOGB0;
2555         }
2556         else
2557         {
2558             // subnormal
2559             const ulong msb = y.vul[MANTISSA_MSB] & 0x0000_FFFF_FFFF_FFFF;
2560             const ulong lsb = y.vul[MANTISSA_LSB];
2561             if (msb)
2562                 return ex - F.EXPBIAS - T.mant_dig + 1 + bsr(msb) + 64;
2563             else
2564                 return ex - F.EXPBIAS - T.mant_dig + 1 + bsr(lsb);
2565         }
2566     }
2567     else static if (F.realFormat == RealFormat.ieeeDouble)
2568     {
2569         if (ex) // If exponent is non-zero
2570         {
2571             if (ex == F.EXPMASK)   // infinity or NaN
2572             {
2573                 if ((y.vul[0] & 0x7FFF_FFFF_FFFF_FFFF) == 0x7FF0_0000_0000_0000)  // +- infinity
2574                     return int.max;
2575                 else // NaN
2576                     return FP_ILOGBNAN;
2577             }
2578             else
2579             {
2580                 return ((ex - F.EXPBIAS) >> 4) - 1;
2581             }
2582         }
2583         else if (!(y.vul[0] & 0x7FFF_FFFF_FFFF_FFFF))
2584         {
2585             // vf is +-0.0
2586             return FP_ILOGB0;
2587         }
2588         else
2589         {
2590             // subnormal
2591             enum MANTISSAMASK_64 = ((cast(ulong) F.MANTISSAMASK_INT) << 32) | 0xFFFF_FFFF;
2592             return ((ex - F.EXPBIAS) >> 4) - T.mant_dig + 1 + bsr(y.vul[0] & MANTISSAMASK_64);
2593         }
2594     }
2595     else static if (F.realFormat == RealFormat.ieeeSingle)
2596     {
2597         if (ex) // If exponent is non-zero
2598         {
2599             if (ex == F.EXPMASK)   // infinity or NaN
2600             {
2601                 if ((y.vui[0] & 0x7FFF_FFFF) == 0x7F80_0000)  // +- infinity
2602                     return int.max;
2603                 else // NaN
2604                     return FP_ILOGBNAN;
2605             }
2606             else
2607             {
2608                 return ((ex - F.EXPBIAS) >> 7) - 1;
2609             }
2610         }
2611         else if (!(y.vui[0] & 0x7FFF_FFFF))
2612         {
2613             // vf is +-0.0
2614             return FP_ILOGB0;
2615         }
2616         else
2617         {
2618             // subnormal
2619             const uint mantissa = y.vui[0] & F.MANTISSAMASK_INT;
2620             return ((ex - F.EXPBIAS) >> 7) - T.mant_dig + 1 + bsr(mantissa);
2621         }
2622     }
2623     else // static if (F.realFormat == RealFormat.ibmExtended)
2624     {
2625         assert(0, "ilogb not implemented");
2626     }
2627 }
2628 /// ditto
2629 int ilogb(T)(const T x) @safe pure nothrow @nogc
2630 if (isIntegral!T && isUnsigned!T)
2631 {
2632     import core.bitop : bsr;
2633     if (x == 0)
2634         return FP_ILOGB0;
2635     else
2636     {
2637         static assert(T.sizeof <= ulong.sizeof, "integer size too large for the current ilogb implementation");
2638         return bsr(x);
2639     }
2640 }
2641 /// ditto
2642 int ilogb(T)(const T x) @safe pure nothrow @nogc
2643 if (isIntegral!T && isSigned!T)
2644 {
2645     import std.traits : Unsigned;
2646     // Note: abs(x) can not be used because the return type is not Unsigned and
2647     //       the return value would be wrong for x == int.min
2648     Unsigned!T absx =  x >= 0 ? x : -x;
2649     return ilogb(absx);
2650 }
2651 
2652 ///
2653 @safe pure unittest
2654 {
2655     assert(ilogb(1) == 0);
2656     assert(ilogb(3) == 1);
2657     assert(ilogb(3.0) == 1);
2658     assert(ilogb(100_000_000) == 26);
2659 
2660     assert(ilogb(0) == FP_ILOGB0);
2661     assert(ilogb(0.0) == FP_ILOGB0);
2662     assert(ilogb(double.nan) == FP_ILOGBNAN);
2663     assert(ilogb(double.infinity) == int.max);
2664 }
2665 
2666 /**
2667 Special return values of $(LREF ilogb).
2668  */
2669 alias FP_ILOGB0   = core.stdc.math.FP_ILOGB0;
2670 /// ditto
2671 alias FP_ILOGBNAN = core.stdc.math.FP_ILOGBNAN;
2672 
2673 ///
2674 @safe pure unittest
2675 {
2676     assert(ilogb(0) == FP_ILOGB0);
2677     assert(ilogb(0.0) == FP_ILOGB0);
2678     assert(ilogb(double.nan) == FP_ILOGBNAN);
2679 }
2680 
2681 @safe nothrow @nogc unittest
2682 {
2683     import std.math : floatTraits, RealFormat;
2684     import std.math.operations : nextUp;
2685     import std.meta : AliasSeq;
2686     import std.typecons : Tuple;
2687     static foreach (F; AliasSeq!(float, double, real))
2688     {{
2689         alias T = Tuple!(F, int);
2690         T[13] vals =   // x, ilogb(x)
2691         [
2692             T(  F.nan     , FP_ILOGBNAN ),
2693             T( -F.nan     , FP_ILOGBNAN ),
2694             T(  F.infinity, int.max     ),
2695             T( -F.infinity, int.max     ),
2696             T(  0.0       , FP_ILOGB0   ),
2697             T( -0.0       , FP_ILOGB0   ),
2698             T(  2.0       , 1           ),
2699             T(  2.0001    , 1           ),
2700             T(  1.9999    , 0           ),
2701             T(  0.5       , -1          ),
2702             T(  123.123   , 6           ),
2703             T( -123.123   , 6           ),
2704             T(  0.123     , -4          ),
2705         ];
2706 
2707         foreach (elem; vals)
2708         {
2709             assert(ilogb(elem[0]) == elem[1]);
2710         }
2711     }}
2712 
2713     // min_normal and subnormals
2714     assert(ilogb(-float.min_normal) == -126);
2715     assert(ilogb(nextUp(-float.min_normal)) == -127);
2716     assert(ilogb(nextUp(-float(0.0))) == -149);
2717     assert(ilogb(-double.min_normal) == -1022);
2718     assert(ilogb(nextUp(-double.min_normal)) == -1023);
2719     assert(ilogb(nextUp(-double(0.0))) == -1074);
2720     static if (floatTraits!(real).realFormat == RealFormat.ieeeExtended)
2721     {
2722         assert(ilogb(-real.min_normal) == -16382);
2723         assert(ilogb(nextUp(-real.min_normal)) == -16383);
2724         assert(ilogb(nextUp(-real(0.0))) == -16445);
2725     }
2726     else static if (floatTraits!(real).realFormat == RealFormat.ieeeDouble)
2727     {
2728         assert(ilogb(-real.min_normal) == -1022);
2729         assert(ilogb(nextUp(-real.min_normal)) == -1023);
2730         assert(ilogb(nextUp(-real(0.0))) == -1074);
2731     }
2732 
2733     // test integer types
2734     assert(ilogb(0) == FP_ILOGB0);
2735     assert(ilogb(int.max) == 30);
2736     assert(ilogb(int.min) == 31);
2737     assert(ilogb(uint.max) == 31);
2738     assert(ilogb(long.max) == 62);
2739     assert(ilogb(long.min) == 63);
2740     assert(ilogb(ulong.max) == 63);
2741 }
2742 
2743 /*******************************************
2744  * Compute n * 2$(SUPERSCRIPT exp)
2745  * References: frexp
2746  */
2747 
2748 pragma(inline, true)
2749 real ldexp(real n, int exp)     @safe pure nothrow @nogc { return core.math.ldexp(n, exp); }
2750 ///ditto
2751 pragma(inline, true)
2752 double ldexp(double n, int exp) @safe pure nothrow @nogc { return core.math.ldexp(n, exp); }
2753 ///ditto
2754 pragma(inline, true)
2755 float ldexp(float n, int exp)   @safe pure nothrow @nogc { return core.math.ldexp(n, exp); }
2756 
2757 ///
2758 @nogc @safe pure nothrow unittest
2759 {
2760     import std.meta : AliasSeq;
2761     static foreach (T; AliasSeq!(float, double, real))
2762     {{
2763         T r;
2764 
2765         r = ldexp(3.0L, 3);
2766         assert(r == 24);
2767 
2768         r = ldexp(cast(T) 3.0, cast(int) 3);
2769         assert(r == 24);
2770 
2771         T n = 3.0;
2772         int exp = 3;
2773         r = ldexp(n, exp);
2774         assert(r == 24);
2775     }}
2776 }
2777 
2778 @safe pure nothrow @nogc unittest
2779 {
2780     import std.math : floatTraits, RealFormat;
2781 
2782     static if (floatTraits!(real).realFormat == RealFormat.ieeeExtended ||
2783                floatTraits!(real).realFormat == RealFormat.ieeeExtended53 ||
2784                floatTraits!(real).realFormat == RealFormat.ieeeQuadruple)
2785     {
2786         assert(ldexp(1.0L, -16384) == 0x1p-16384L);
2787         assert(ldexp(1.0L, -16382) == 0x1p-16382L);
2788         int x;
2789         real n = frexp(0x1p-16384L, x);
2790         assert(n == 0.5L);
2791         assert(x==-16383);
2792         assert(ldexp(n, x)==0x1p-16384L);
2793     }
2794     else static if (floatTraits!(real).realFormat == RealFormat.ieeeDouble)
2795     {
2796         assert(ldexp(1.0L, -1024) == 0x1p-1024L);
2797         assert(ldexp(1.0L, -1022) == 0x1p-1022L);
2798         int x;
2799         real n = frexp(0x1p-1024L, x);
2800         assert(n == 0.5L);
2801         assert(x==-1023);
2802         assert(ldexp(n, x)==0x1p-1024L);
2803     }
2804     else static assert(false, "Floating point type real not supported");
2805 }
2806 
2807 /* workaround https://issues.dlang.org/show_bug.cgi?id=14718
2808    float parsing depends on platform strtold
2809 @safe pure nothrow @nogc unittest
2810 {
2811     assert(ldexp(1.0, -1024) == 0x1p-1024);
2812     assert(ldexp(1.0, -1022) == 0x1p-1022);
2813     int x;
2814     double n = frexp(0x1p-1024, x);
2815     assert(n == 0.5);
2816     assert(x==-1023);
2817     assert(ldexp(n, x)==0x1p-1024);
2818 }
2819 
2820 @safe pure nothrow @nogc unittest
2821 {
2822     assert(ldexp(1.0f, -128) == 0x1p-128f);
2823     assert(ldexp(1.0f, -126) == 0x1p-126f);
2824     int x;
2825     float n = frexp(0x1p-128f, x);
2826     assert(n == 0.5f);
2827     assert(x==-127);
2828     assert(ldexp(n, x)==0x1p-128f);
2829 }
2830 */
2831 
2832 @safe @nogc nothrow unittest
2833 {
2834     import std.math.operations : isClose;
2835 
2836     static real[3][] vals =    // value,exp,ldexp
2837     [
2838     [    0,    0,    0],
2839     [    1,    0,    1],
2840     [    -1,    0,    -1],
2841     [    1,    1,    2],
2842     [    123,    10,    125952],
2843     [    real.max,    int.max,    real.infinity],
2844     [    real.max,    -int.max,    0],
2845     [    real.min_normal,    -int.max,    0],
2846     ];
2847     int i;
2848 
2849     for (i = 0; i < vals.length; i++)
2850     {
2851         real x = vals[i][0];
2852         int exp = cast(int) vals[i][1];
2853         real z = vals[i][2];
2854         real l = ldexp(x, exp);
2855 
2856         assert(isClose(z, l, 1e-6));
2857     }
2858 
2859     real function(real, int) pldexp = &ldexp;
2860     assert(pldexp != null);
2861 }
2862 
2863 private
2864 {
2865     // Coefficients shared across log(), log2(), log10().
2866     template LogCoeffs(T)
2867     {
2868         import std.math : floatTraits, RealFormat;
2869 
2870         static if (floatTraits!T.realFormat == RealFormat.ieeeQuadruple)
2871         {
2872             // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x)
2873             // Theoretical peak relative error = 5.3e-37
2874             static immutable real[13] logP = [
2875                 1.313572404063446165910279910527789794488E4L,
2876                 7.771154681358524243729929227226708890930E4L,
2877                 2.014652742082537582487669938141683759923E5L,
2878                 3.007007295140399532324943111654767187848E5L,
2879                 2.854829159639697837788887080758954924001E5L,
2880                 1.797628303815655343403735250238293741397E5L,
2881                 7.594356839258970405033155585486712125861E4L,
2882                 2.128857716871515081352991964243375186031E4L,
2883                 3.824952356185897735160588078446136783779E3L,
2884                 4.114517881637811823002128927449878962058E2L,
2885                 2.321125933898420063925789532045674660756E1L,
2886                 4.998469661968096229986658302195402690910E-1L,
2887                 1.538612243596254322971797716843006400388E-6L
2888             ];
2889             static immutable real[13] logQ = [
2890                 3.940717212190338497730839731583397586124E4L,
2891                 2.626900195321832660448791748036714883242E5L,
2892                 7.777690340007566932935753241556479363645E5L,
2893                 1.347518538384329112529391120390701166528E6L,
2894                 1.514882452993549494932585972882995548426E6L,
2895                 1.158019977462989115839826904108208787040E6L,
2896                 6.132189329546557743179177159925690841200E5L,
2897                 2.248234257620569139969141618556349415120E5L,
2898                 5.605842085972455027590989944010492125825E4L,
2899                 9.147150349299596453976674231612674085381E3L,
2900                 9.104928120962988414618126155557301584078E2L,
2901                 4.839208193348159620282142911143429644326E1L,
2902                 1.0
2903             ];
2904 
2905             // log2 uses the same coefficients as log.
2906             alias log2P = logP;
2907             alias log2Q = logQ;
2908 
2909             // log10 uses the same coefficients as log.
2910             alias log10P = logP;
2911             alias log10Q = logQ;
2912 
2913             // Coefficients for log(x) = z + z^^3 R(z^^2)/S(z^^2)
2914             // where z = 2(x-1)/(x+1)
2915             // Theoretical peak relative error = 1.1e-35
2916             static immutable real[6] logR = [
2917                 1.418134209872192732479751274970992665513E5L,
2918                 -8.977257995689735303686582344659576526998E4L,
2919                 2.048819892795278657810231591630928516206E4L,
2920                 -2.024301798136027039250415126250455056397E3L,
2921                 8.057002716646055371965756206836056074715E1L,
2922                 -8.828896441624934385266096344596648080902E-1L
2923             ];
2924             static immutable real[7] logS = [
2925                 1.701761051846631278975701529965589676574E6L,
2926                 -1.332535117259762928288745111081235577029E6L,
2927                 4.001557694070773974936904547424676279307E5L,
2928                 -5.748542087379434595104154610899551484314E4L,
2929                 3.998526750980007367835804959888064681098E3L,
2930                 -1.186359407982897997337150403816839480438E2L,
2931                 1.0
2932             ];
2933         }
2934         else static if (floatTraits!T.realFormat == RealFormat.ieeeExtended ||
2935                         floatTraits!T.realFormat == RealFormat.ieeeExtended53)
2936         {
2937             // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x)
2938             // Theoretical peak relative error = 2.32e-20
2939             static immutable real[7] logP = [
2940                 2.0039553499201281259648E1L,
2941                 5.7112963590585538103336E1L,
2942                 6.0949667980987787057556E1L,
2943                 2.9911919328553073277375E1L,
2944                 6.5787325942061044846969E0L,
2945                 4.9854102823193375972212E-1L,
2946                 4.5270000862445199635215E-5L,
2947             ];
2948             static immutable real[7] logQ = [
2949                 6.0118660497603843919306E1L,
2950                 2.1642788614495947685003E2L,
2951                 3.0909872225312059774938E2L,
2952                 2.2176239823732856465394E2L,
2953                 8.3047565967967209469434E1L,
2954                 1.5062909083469192043167E1L,
2955                 1.0000000000000000000000E0L,
2956             ];
2957 
2958             // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x)
2959             // Theoretical peak relative error = 6.2e-22
2960             static immutable real[7] log2P = [
2961                 1.0747524399916215149070E2L,
2962                 3.4258224542413922935104E2L,
2963                 4.2401812743503691187826E2L,
2964                 2.5620629828144409632571E2L,
2965                 7.7671073698359539859595E1L,
2966                 1.0767376367209449010438E1L,
2967                 4.9962495940332550844739E-1L,
2968             ];
2969             static immutable real[8] log2Q = [
2970                 3.2242573199748645407652E2L,
2971                 1.2695660352705325274404E3L,
2972                 2.0307734695595183428202E3L,
2973                 1.6911722418503949084863E3L,
2974                 7.7952888181207260646090E2L,
2975                 1.9444210022760132894510E2L,
2976                 2.3479774160285863271658E1L,
2977                 1.0000000000000000000000E0,
2978             ];
2979 
2980             // log10 uses the same coefficients as log2.
2981             alias log10P = log2P;
2982             alias log10Q = log2Q;
2983 
2984             // Coefficients for log(x) = z + z^^3 R(z^^2)/S(z^^2)
2985             // where z = 2(x-1)/(x+1)
2986             // Theoretical peak relative error = 6.16e-22
2987             static immutable real[4] logR = [
2988                -3.5717684488096787370998E1L,
2989                 1.0777257190312272158094E1L,
2990                -7.1990767473014147232598E-1L,
2991                 1.9757429581415468984296E-3L,
2992             ];
2993             static immutable real[4] logS = [
2994                -4.2861221385716144629696E2L,
2995                 1.9361891836232102174846E2L,
2996                -2.6201045551331104417768E1L,
2997                 1.0000000000000000000000E0L,
2998             ];
2999         }
3000         else static if (floatTraits!T.realFormat == RealFormat.ieeeDouble)
3001         {
3002             // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x)
3003             static immutable double[6] logP = [
3004                 7.70838733755885391666E0,
3005                 1.79368678507819816313E1,
3006                 1.44989225341610930846E1,
3007                 4.70579119878881725854E0,
3008                 4.97494994976747001425E-1,
3009                 1.01875663804580931796E-4,
3010             ];
3011             static immutable double[6] logQ = [
3012                 2.31251620126765340583E1,
3013                 7.11544750618563894466E1,
3014                 8.29875266912776603211E1,
3015                 4.52279145837532221105E1,
3016                 1.12873587189167450590E1,
3017                 1.00000000000000000000E0,
3018             ];
3019 
3020             // log2 uses the same coefficients as log.
3021             alias log2P = logP;
3022             alias log2Q = logQ;
3023 
3024             // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x)
3025             static immutable double[7] log10P = [
3026                 4.58482948458143443514E-5,
3027                 4.98531067254050724270E-1,
3028                 6.56312093769992875930E0,
3029                 2.97877425097986925891E1,
3030                 6.06127134467767258030E1,
3031                 5.67349287391754285487E1,
3032                 1.98892446572874072159E1,
3033             ];
3034             static immutable double[7] log10Q = [
3035                 1.00000000000000000000E0,
3036                 1.50314182634250003249E1,
3037                 8.27410449222435217021E1,
3038                 2.20664384982121929218E2,
3039                 3.07254189979530058263E2,
3040                 2.14955586696422947765E2,
3041                 5.96677339718622216300E1,
3042             ];
3043 
3044             // Coefficients for log(x) = z + z^^3 R(z)/S(z)
3045             // where z = 2(x-1)/(x+1)
3046             static immutable double[3] logR = [
3047                 -6.41409952958715622951E1,
3048                 1.63866645699558079767E1,
3049                 -7.89580278884799154124E-1,
3050             ];
3051             static immutable double[4] logS = [
3052                 -7.69691943550460008604E2,
3053                 3.12093766372244180303E2,
3054                 -3.56722798256324312549E1,
3055                 1.00000000000000000000E0,
3056             ];
3057         }
3058         else static if (floatTraits!T.realFormat == RealFormat.ieeeSingle)
3059         {
3060             // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)
3061             static immutable float[9] logP = [
3062                  3.3333331174E-1,
3063                 -2.4999993993E-1,
3064                  2.0000714765E-1,
3065                 -1.6668057665E-1,
3066                  1.4249322787E-1,
3067                 -1.2420140846E-1,
3068                  1.1676998740E-1,
3069                 -1.1514610310E-1,
3070                  7.0376836292E-2,
3071             ];
3072 
3073             // log2 and log10 uses the same coefficients as log.
3074             alias log2P = logP;
3075             alias log10P = logP;
3076         }
3077         else
3078             static assert(0, "no coefficients for log()");
3079     }
3080 }
3081 
3082 /**************************************
3083  * Calculate the natural logarithm of x.
3084  *
3085  *    $(TABLE_SV
3086  *    $(TR $(TH x)            $(TH log(x))    $(TH divide by 0?) $(TH invalid?))
3087  *    $(TR $(TD $(PLUSMN)0.0) $(TD -$(INFIN)) $(TD yes)          $(TD no))
3088  *    $(TR $(TD $(LT)0.0)     $(TD $(NAN))    $(TD no)           $(TD yes))
3089  *    $(TR $(TD +$(INFIN))    $(TD +$(INFIN)) $(TD no)           $(TD no))
3090  *    )
3091  */
3092 pragma(inline, true)
3093 real log(real x) @safe pure nothrow @nogc
3094 {
3095     version (INLINE_YL2X)
3096     {
3097         import std.math.constants : LN2;
3098         return core.math.yl2x(x, LN2);
3099     }
3100     else
3101         return logImpl(x);
3102 }
3103 
3104 /// ditto
3105 pragma(inline, true)
3106 double log(double x) @safe pure nothrow @nogc { return __ctfe ? cast(double) log(cast(real) x) : logImpl(x); }
3107 
3108 /// ditto
3109 pragma(inline, true)
3110 float log(float x) @safe pure nothrow @nogc { return __ctfe ? cast(float) log(cast(real) x) : logImpl(x); }
3111 
3112 // @@@DEPRECATED_[2.112.0]@@@
3113 deprecated("`std.math.exponential.log` called with argument types `(int)` matches both "
3114            ~ "`log(real)`, `log(double)`, and `log(float)`. Cast argument to floating point type instead.")
3115 real log(int x) @safe pure nothrow @nogc { return log(cast(real) x); }
3116 // @@@DEPRECATED_[2.112.0]@@@
3117 deprecated("`std.math.exponential.log` called with argument types `(uint)` matches both "
3118            ~ "`log(real)`, `log(double)`, and `log(float)`. Cast argument to floating point type instead.")
3119 real log(uint x) @safe pure nothrow @nogc { return log(cast(real) x); }
3120 // @@@DEPRECATED_[2.112.0]@@@
3121 deprecated("`std.math.exponential.log` called with argument types `(long)` matches both "
3122            ~ "`log(real)`, `log(double)`, and `log(float)`. Cast argument to floating point type instead.")
3123 real log(long x) @safe pure nothrow @nogc { return log(cast(real) x); }
3124 // @@@DEPRECATED_[2.112.0]@@@
3125 deprecated("`std.math.exponential.log` called with argument types `(ulong)` matches both "
3126            ~ "`log(real)`, `log(double)`, and `log(float)`. Cast argument to floating point type instead.")
3127 real log(ulong x) @safe pure nothrow @nogc { return log(cast(real) x); }
3128 
3129 ///
3130 @safe pure nothrow @nogc unittest
3131 {
3132     import std.math.operations : feqrel;
3133     import std.math.constants : E;
3134 
3135     assert(feqrel(log(E), 1) >= real.mant_dig - 1);
3136 }
3137 
3138 private T logImpl(T)(T x) @safe pure nothrow @nogc
3139 {
3140     import std.math.constants : SQRT1_2;
3141     import std.math.algebraic : poly;
3142     import std.math.traits : isInfinity, isNaN, signbit;
3143     import std.math : floatTraits, RealFormat;
3144 
3145     alias coeffs = LogCoeffs!T;
3146     alias F = floatTraits!T;
3147 
3148     static if (F.realFormat == RealFormat.ieeeExtended ||
3149                F.realFormat == RealFormat.ieeeExtended53 ||
3150                F.realFormat == RealFormat.ieeeQuadruple)
3151     {
3152         // C1 + C2 = LN2.
3153         enum T C1 = 6.93145751953125E-1L;
3154         enum T C2 = 1.428606820309417232121458176568075500134E-6L;
3155     }
3156     else static if (F.realFormat == RealFormat.ieeeDouble)
3157     {
3158         enum T C1 = 0.693359375;
3159         enum T C2 = -2.121944400546905827679e-4;
3160     }
3161     else static if (F.realFormat == RealFormat.ieeeSingle)
3162     {
3163         enum T C1 = 0.693359375;
3164         enum T C2 = -2.12194440e-4;
3165     }
3166     else
3167         static assert(0, "Not implemented for this architecture");
3168 
3169     // Special cases.
3170     if (isNaN(x))
3171         return x;
3172     if (isInfinity(x) && !signbit(x))
3173         return x;
3174     if (x == 0.0)
3175         return -T.infinity;
3176     if (x < 0.0)
3177         return T.nan;
3178 
3179     // Separate mantissa from exponent.
3180     // Note, frexp is used so that denormal numbers will be handled properly.
3181     T y, z;
3182     int exp;
3183 
3184     x = frexp(x, exp);
3185 
3186     static if (F.realFormat == RealFormat.ieeeDouble ||
3187                F.realFormat == RealFormat.ieeeExtended ||
3188                F.realFormat == RealFormat.ieeeExtended53 ||
3189                F.realFormat == RealFormat.ieeeQuadruple)
3190     {
3191         // Logarithm using log(x) = z + z^^3 R(z) / S(z),
3192         // where z = 2(x - 1)/(x + 1)
3193         if ((exp > 2) || (exp < -2))
3194         {
3195             if (x < SQRT1_2)
3196             {   // 2(2x - 1)/(2x + 1)
3197                 exp -= 1;
3198                 z = x - 0.5;
3199                 y = 0.5 * z + 0.5;
3200             }
3201             else
3202             {   // 2(x - 1)/(x + 1)
3203                 z = x - 0.5;
3204                 z -= 0.5;
3205                 y = 0.5 * x  + 0.5;
3206             }
3207             x = z / y;
3208             z = x * x;
3209             z = x * (z * poly(z, coeffs.logR) / poly(z, coeffs.logS));
3210             z += exp * C2;
3211             z += x;
3212             z += exp * C1;
3213 
3214             return z;
3215         }
3216     }
3217 
3218     // Logarithm using log(1 + x) = x - .5x^^2 + x^^3 P(x) / Q(x)
3219     if (x < SQRT1_2)
3220     {
3221         exp -= 1;
3222         x = 2.0 * x - 1.0;
3223     }
3224     else
3225     {
3226         x = x - 1.0;
3227     }
3228     z = x * x;
3229     static if (F.realFormat == RealFormat.ieeeSingle)
3230         y = x * (z * poly(x, coeffs.logP));
3231     else
3232         y = x * (z * poly(x, coeffs.logP) / poly(x, coeffs.logQ));
3233     y += exp * C2;
3234     z = y - 0.5 * z;
3235 
3236     // Note, the sum of above terms does not exceed x/4,
3237     // so it contributes at most about 1/4 lsb to the error.
3238     z += x;
3239     z += exp * C1;
3240 
3241     return z;
3242 }
3243 
3244 /**************************************
3245  * Calculate the base-10 logarithm of x.
3246  *
3247  *      $(TABLE_SV
3248  *      $(TR $(TH x)            $(TH log10(x))  $(TH divide by 0?) $(TH invalid?))
3249  *      $(TR $(TD $(PLUSMN)0.0) $(TD -$(INFIN)) $(TD yes)          $(TD no))
3250  *      $(TR $(TD $(LT)0.0)     $(TD $(NAN))    $(TD no)           $(TD yes))
3251  *      $(TR $(TD +$(INFIN))    $(TD +$(INFIN)) $(TD no)           $(TD no))
3252  *      )
3253  */
3254 pragma(inline, true)
3255 real log10(real x) @safe pure nothrow @nogc
3256 {
3257     version (INLINE_YL2X)
3258     {
3259         import std.math.constants : LOG2;
3260         return core.math.yl2x(x, LOG2);
3261     }
3262     else
3263         return log10Impl(x);
3264 }
3265 
3266 /// ditto
3267 pragma(inline, true)
3268 double log10(double x) @safe pure nothrow @nogc { return __ctfe ? cast(double) log10(cast(real) x) : log10Impl(x); }
3269 
3270 /// ditto
3271 pragma(inline, true)
3272 float log10(float x) @safe pure nothrow @nogc { return __ctfe ? cast(float) log10(cast(real) x) : log10Impl(x); }
3273 
3274 // @@@DEPRECATED_[2.112.0]@@@
3275 deprecated("`std.math.exponential.log10` called with argument types `(int)` matches both "
3276            ~ "`log10(real)`, `log10(double)`, and `log10(float)`. Cast argument to floating point type instead.")
3277 real log10(int x) @safe pure nothrow @nogc { return log10(cast(real) x); }
3278 // @@@DEPRECATED_[2.112.0]@@@
3279 deprecated("`std.math.exponential.log10` called with argument types `(uint)` matches both "
3280            ~ "`log10(real)`, `log10(double)`, and `log10(float)`. Cast argument to floating point type instead.")
3281 real log10(uint x) @safe pure nothrow @nogc { return log10(cast(real) x); }
3282 // @@@DEPRECATED_[2.112.0]@@@
3283 deprecated("`std.math.exponential.log10` called with argument types `(long)` matches both "
3284            ~ "`log10(real)`, `log10(double)`, and `log10(float)`. Cast argument to floating point type instead.")
3285 real log10(long x) @safe pure nothrow @nogc { return log10(cast(real) x); }
3286 // @@@DEPRECATED_[2.112.0]@@@
3287 deprecated("`std.math.exponential.log10` called with argument types `(ulong)` matches both "
3288            ~ "`log10(real)`, `log10(double)`, and `log10(float)`. Cast argument to floating point type instead.")
3289 real log10(ulong x) @safe pure nothrow @nogc { return log10(cast(real) x); }
3290 
3291 ///
3292 @safe pure nothrow @nogc unittest
3293 {
3294     import std.math.algebraic : fabs;
3295 
3296     assert(fabs(log10(1000.0L) - 3) < .000001);
3297 }
3298 
3299 private T log10Impl(T)(T x) @safe pure nothrow @nogc
3300 {
3301     import std.math.constants : SQRT1_2;
3302     import std.math.algebraic : poly;
3303     import std.math.traits : isNaN, isInfinity, signbit;
3304     import std.math : floatTraits, RealFormat;
3305 
3306     alias coeffs = LogCoeffs!T;
3307     alias F = floatTraits!T;
3308 
3309     static if (F.realFormat == RealFormat.ieeeExtended ||
3310                F.realFormat == RealFormat.ieeeExtended53 ||
3311                F.realFormat == RealFormat.ieeeQuadruple)
3312     {
3313         // log10(2) split into two parts.
3314         enum T L102A =  0.3125L;
3315         enum T L102B = -1.14700043360188047862611052755069732318101185E-2L;
3316 
3317         // log10(e) split into two parts.
3318         enum T L10EA =  0.5L;
3319         enum T L10EB = -6.570551809674817234887108108339491770560299E-2L;
3320     }
3321     else static if (F.realFormat == RealFormat.ieeeDouble ||
3322                     F.realFormat == RealFormat.ieeeSingle)
3323     {
3324         enum T L102A =  3.0078125E-1;
3325         enum T L102B = 2.48745663981195213739E-4;
3326 
3327         enum T L10EA =  4.3359375E-1;
3328         enum T L10EB = 7.00731903251827651129E-4;
3329     }
3330     else
3331         static assert(0, "Not implemented for this architecture");
3332 
3333     // Special cases are the same as for log.
3334     if (isNaN(x))
3335         return x;
3336     if (isInfinity(x) && !signbit(x))
3337         return x;
3338     if (x == 0.0)
3339         return -T.infinity;
3340     if (x < 0.0)
3341         return T.nan;
3342 
3343     // Separate mantissa from exponent.
3344     // Note, frexp is used so that denormal numbers will be handled properly.
3345     T y, z;
3346     int exp;
3347 
3348     x = frexp(x, exp);
3349 
3350     static if (F.realFormat == RealFormat.ieeeExtended ||
3351                F.realFormat == RealFormat.ieeeExtended53 ||
3352                F.realFormat == RealFormat.ieeeQuadruple)
3353     {
3354         // Logarithm using log(x) = z + z^^3 R(z) / S(z),
3355         // where z = 2(x - 1)/(x + 1)
3356         if ((exp > 2) || (exp < -2))
3357         {
3358             if (x < SQRT1_2)
3359             {   // 2(2x - 1)/(2x + 1)
3360                 exp -= 1;
3361                 z = x - 0.5;
3362                 y = 0.5 * z + 0.5;
3363             }
3364             else
3365             {   // 2(x - 1)/(x + 1)
3366                 z = x - 0.5;
3367                 z -= 0.5;
3368                 y = 0.5 * x  + 0.5;
3369             }
3370             x = z / y;
3371             z = x * x;
3372             y = x * (z * poly(z, coeffs.logR) / poly(z, coeffs.logS));
3373             goto Ldone;
3374         }
3375     }
3376 
3377     // Logarithm using log(1 + x) = x - .5x^^2 + x^^3 P(x) / Q(x)
3378     if (x < SQRT1_2)
3379     {
3380         exp -= 1;
3381         x = 2.0 * x - 1.0;
3382     }
3383     else
3384         x = x - 1.0;
3385 
3386     z = x * x;
3387     static if (F.realFormat == RealFormat.ieeeSingle)
3388         y = x * (z * poly(x, coeffs.log10P));
3389     else
3390         y = x * (z * poly(x, coeffs.log10P) / poly(x, coeffs.log10Q));
3391     y = y - 0.5 * z;
3392 
3393     // Multiply log of fraction by log10(e) and base 2 exponent by log10(2).
3394     // This sequence of operations is critical and it may be horribly
3395     // defeated by some compiler optimizers.
3396 Ldone:
3397     z = y * L10EB;
3398     z += x * L10EB;
3399     z += exp * L102B;
3400     z += y * L10EA;
3401     z += x * L10EA;
3402     z += exp * L102A;
3403 
3404     return z;
3405 }
3406 
3407 /**
3408  * Calculates the natural logarithm of 1 + x.
3409  *
3410  * For very small x, log1p(x) will be more accurate than
3411  * log(1 + x).
3412  *
3413  *  $(TABLE_SV
3414  *  $(TR $(TH x)            $(TH log1p(x))     $(TH divide by 0?) $(TH invalid?))
3415  *  $(TR $(TD $(PLUSMN)0.0) $(TD $(PLUSMN)0.0) $(TD no)           $(TD no))
3416  *  $(TR $(TD -1.0)         $(TD -$(INFIN))    $(TD yes)          $(TD no))
3417  *  $(TR $(TD $(LT)-1.0)    $(TD -$(NAN))      $(TD no)           $(TD yes))
3418  *  $(TR $(TD +$(INFIN))    $(TD +$(INFIN))    $(TD no)           $(TD no))
3419  *  )
3420  */
3421 pragma(inline, true)
3422 real log1p(real x) @safe pure nothrow @nogc
3423 {
3424     version (INLINE_YL2X)
3425     {
3426         // On x87, yl2xp1 is valid if and only if -0.5 <= lg(x) <= 0.5,
3427         //    ie if -0.29 <= x <= 0.414
3428         import std.math.constants : LN2;
3429         return (core.math.fabs(x) <= 0.25)  ? core.math.yl2xp1(x, LN2) : core.math.yl2x(x+1, LN2);
3430     }
3431     else
3432         return log1pImpl(x);
3433 }
3434 
3435 /// ditto
3436 pragma(inline, true)
3437 double log1p(double x) @safe pure nothrow @nogc { return __ctfe ? cast(double) log1p(cast(real) x) : log1pImpl(x); }
3438 
3439 /// ditto
3440 pragma(inline, true)
3441 float log1p(float x) @safe pure nothrow @nogc { return __ctfe ? cast(float) log1p(cast(real) x) : log1pImpl(x); }
3442 
3443 // @@@DEPRECATED_[2.112.0]@@@
3444 deprecated("`std.math.exponential.log1p` called with argument types `(int)` matches both "
3445            ~ "`log1p(real)`, `log1p(double)`, and `log1p(float)`. Cast argument to floating point type instead.")
3446 real log1p(int x) @safe pure nothrow @nogc { return log1p(cast(real) x); }
3447 // @@@DEPRECATED_[2.112.0]@@@
3448 deprecated("`std.math.exponential.log1p` called with argument types `(uint)` matches both "
3449            ~ "`log1p(real)`, `log1p(double)`, and `log1p(float)`. Cast argument to floating point type instead.")
3450 real log1p(uint x) @safe pure nothrow @nogc { return log1p(cast(real) x); }
3451 // @@@DEPRECATED_[2.112.0]@@@
3452 deprecated("`std.math.exponential.log1p` called with argument types `(long)` matches both "
3453            ~ "`log1p(real)`, `log1p(double)`, and `log1p(float)`. Cast argument to floating point type instead.")
3454 real log1p(long x) @safe pure nothrow @nogc { return log1p(cast(real) x); }
3455 // @@@DEPRECATED_[2.112.0]@@@
3456 deprecated("`std.math.exponential.log1p` called with argument types `(ulong)` matches both "
3457            ~ "`log1p(real)`, `log1p(double)`, and `log1p(float)`. Cast argument to floating point type instead.")
3458 real log1p(ulong x) @safe pure nothrow @nogc { return log1p(cast(real) x); }
3459 
3460 ///
3461 @safe pure unittest
3462 {
3463     import std.math.traits : isIdentical, isNaN;
3464     import std.math.operations : feqrel;
3465 
3466     assert(isIdentical(log1p(0.0), 0.0));
3467     assert(log1p(1.0).feqrel(0.69314) > 16);
3468 
3469     assert(log1p(-1.0) == -real.infinity);
3470     assert(isNaN(log1p(-2.0)));
3471     assert(log1p(real.nan) is real.nan);
3472     assert(log1p(-real.nan) is -real.nan);
3473     assert(log1p(real.infinity) == real.infinity);
3474 }
3475 
3476 private T log1pImpl(T)(T x) @safe pure nothrow @nogc
3477 {
3478     import std.math.traits : isNaN, isInfinity, signbit;
3479 
3480     // Special cases.
3481     if (isNaN(x) || x == 0.0)
3482         return x;
3483     if (isInfinity(x) && !signbit(x))
3484         return x;
3485     if (x == -1.0)
3486         return -T.infinity;
3487     if (x < -1.0)
3488         return T.nan;
3489 
3490     return logImpl(x + 1.0);
3491 }
3492 
3493 /***************************************
3494  * Calculates the base-2 logarithm of x:
3495  * $(SUB log, 2)x
3496  *
3497  *  $(TABLE_SV
3498  *  $(TR $(TH x)            $(TH log2(x))   $(TH divide by 0?) $(TH invalid?))
3499  *  $(TR $(TD $(PLUSMN)0.0) $(TD -$(INFIN)) $(TD yes)          $(TD no) )
3500  *  $(TR $(TD $(LT)0.0)     $(TD $(NAN))    $(TD no)           $(TD yes) )
3501  *  $(TR $(TD +$(INFIN))    $(TD +$(INFIN)) $(TD no)           $(TD no) )
3502  *  )
3503  */
3504 pragma(inline, true)
3505 real log2(real x) @safe pure nothrow @nogc
3506 {
3507     version (INLINE_YL2X)
3508         return core.math.yl2x(x, 1.0L);
3509     else
3510         return log2Impl(x);
3511 }
3512 
3513 /// ditto
3514 pragma(inline, true)
3515 double log2(double x) @safe pure nothrow @nogc { return __ctfe ? cast(double) log2(cast(real) x) : log2Impl(x); }
3516 
3517 /// ditto
3518 pragma(inline, true)
3519 float log2(float x) @safe pure nothrow @nogc { return __ctfe ? cast(float) log2(cast(real) x) : log2Impl(x); }
3520 
3521 // @@@DEPRECATED_[2.112.0]@@@
3522 deprecated("`std.math.exponential.log2` called with argument types `(int)` matches both "
3523            ~ "`log2(real)`, `log2(double)`, and `log2(float)`. Cast argument to floating point type instead.")
3524 real log2(int x) @safe pure nothrow @nogc { return log2(cast(real) x); }
3525 // @@@DEPRECATED_[2.112.0]@@@
3526 deprecated("`std.math.exponential.log2` called with argument types `(uint)` matches both "
3527            ~ "`log2(real)`, `log2(double)`, and `log2(float)`. Cast argument to floating point type instead.")
3528 real log2(uint x) @safe pure nothrow @nogc { return log2(cast(real) x); }
3529 // @@@DEPRECATED_[2.112.0]@@@
3530 deprecated("`std.math.exponential.log2` called with argument types `(long)` matches both "
3531            ~ "`log2(real)`, `log2(double)`, and `log2(float)`. Cast argument to floating point type instead.")
3532 real log2(long x) @safe pure nothrow @nogc { return log2(cast(real) x); }
3533 // @@@DEPRECATED_[2.112.0]@@@
3534 deprecated("`std.math.exponential.log2` called with argument types `(ulong)` matches both "
3535            ~ "`log2(real)`, `log2(double)`, and `log2(float)`. Cast argument to floating point type instead.")
3536 real log2(ulong x) @safe pure nothrow @nogc { return log2(cast(real) x); }
3537 
3538 ///
3539 @safe unittest
3540 {
3541     import std.math.operations : isClose;
3542 
3543     assert(isClose(log2(1024.0L), 10));
3544 }
3545 
3546 @safe @nogc nothrow unittest
3547 {
3548     import std.math.operations : isClose;
3549 
3550     // check if values are equal to 19 decimal digits of precision
3551     assert(isClose(log2(1024.0L), 10, 1e-18));
3552 }
3553 
3554 private T log2Impl(T)(T x) @safe pure nothrow @nogc
3555 {
3556     import std.math.traits : isNaN, isInfinity, signbit;
3557     import std.math.constants : SQRT1_2, LOG2E;
3558     import std.math.algebraic : poly;
3559     import std.math : floatTraits, RealFormat;
3560 
3561     alias coeffs = LogCoeffs!T;
3562     alias F = floatTraits!T;
3563 
3564     // Special cases are the same as for log.
3565     if (isNaN(x))
3566         return x;
3567     if (isInfinity(x) && !signbit(x))
3568         return x;
3569     if (x == 0.0)
3570         return -T.infinity;
3571     if (x < 0.0)
3572         return T.nan;
3573 
3574     // Separate mantissa from exponent.
3575     // Note, frexp is used so that denormal numbers will be handled properly.
3576     T y, z;
3577     int exp;
3578 
3579     x = frexp(x, exp);
3580 
3581     static if (F.realFormat == RealFormat.ieeeDouble ||
3582                F.realFormat == RealFormat.ieeeExtended ||
3583                F.realFormat == RealFormat.ieeeExtended53 ||
3584                F.realFormat == RealFormat.ieeeQuadruple)
3585     {
3586         // Logarithm using log(x) = z + z^^3 R(z) / S(z),
3587         // where z = 2(x - 1)/(x + 1)
3588         if ((exp > 2) || (exp < -2))
3589         {
3590             if (x < SQRT1_2)
3591             {   // 2(2x - 1)/(2x + 1)
3592                 exp -= 1;
3593                 z = x - 0.5;
3594                 y = 0.5 * z + 0.5;
3595             }
3596             else
3597             {   // 2(x - 1)/(x + 1)
3598                 z = x - 0.5;
3599                 z -= 0.5;
3600                 y = 0.5 * x  + 0.5;
3601             }
3602             x = z / y;
3603             z = x * x;
3604             y = x * (z * poly(z, coeffs.logR) / poly(z, coeffs.logS));
3605             goto Ldone;
3606         }
3607     }
3608 
3609     // Logarithm using log(1 + x) = x - .5x^^2 + x^^3 P(x) / Q(x)
3610     if (x < SQRT1_2)
3611     {
3612         exp -= 1;
3613         x = 2.0 * x - 1.0;
3614     }
3615     else
3616         x = x - 1.0;
3617 
3618     z = x * x;
3619     static if (F.realFormat == RealFormat.ieeeSingle)
3620         y = x * (z * poly(x, coeffs.log2P));
3621     else
3622         y = x * (z * poly(x, coeffs.log2P) / poly(x, coeffs.log2Q));
3623     y = y - 0.5 * z;
3624 
3625     // Multiply log of fraction by log10(e) and base 2 exponent by log10(2).
3626     // This sequence of operations is critical and it may be horribly
3627     // defeated by some compiler optimizers.
3628 Ldone:
3629     z = y * (LOG2E - 1.0);
3630     z += x * (LOG2E - 1.0);
3631     z += y;
3632     z += x;
3633     z += exp;
3634 
3635     return z;
3636 }
3637 
3638 /*****************************************
3639  * Extracts the exponent of x as a signed integral value.
3640  *
3641  * If x is subnormal, it is treated as if it were normalized.
3642  * For a positive, finite x:
3643  *
3644  * 1 $(LT)= $(I x) * FLT_RADIX$(SUPERSCRIPT -logb(x)) $(LT) FLT_RADIX
3645  *
3646  *      $(TABLE_SV
3647  *      $(TR $(TH x)                 $(TH logb(x))   $(TH divide by 0?) )
3648  *      $(TR $(TD $(PLUSMN)$(INFIN)) $(TD +$(INFIN)) $(TD no))
3649  *      $(TR $(TD $(PLUSMN)0.0)      $(TD -$(INFIN)) $(TD yes) )
3650  *      )
3651  */
3652 pragma(inline, true)
3653 real logb(real x) @trusted pure nothrow @nogc
3654 {
3655     version (InlineAsm_X87_MSVC)
3656         return logbAsm(x);
3657     else
3658         return logbImpl(x);
3659 }
3660 
3661 /// ditto
3662 pragma(inline, true)
3663 double logb(double x) @trusted pure nothrow @nogc { return logbImpl(x); }
3664 
3665 /// ditto
3666 pragma(inline, true)
3667 float logb(float x) @trusted pure nothrow @nogc { return logbImpl(x); }
3668 
3669 ///
3670 @safe @nogc nothrow unittest
3671 {
3672     assert(logb(1.0) == 0);
3673     assert(logb(100.0) == 6);
3674 
3675     assert(logb(0.0) == -real.infinity);
3676     assert(logb(real.infinity) == real.infinity);
3677     assert(logb(-real.infinity) == real.infinity);
3678 }
3679 
3680 @safe @nogc nothrow unittest
3681 {
3682     import std.meta : AliasSeq;
3683     import std.typecons : Tuple;
3684     import std.math.traits : isNaN;
3685     static foreach (F; AliasSeq!(float, double, real))
3686     {{
3687         alias T = Tuple!(F, F);
3688         T[17] vals =   // x, logb(x)
3689         [
3690             T(1.0          , 0          ),
3691             T(100.0        , 6          ),
3692             T(0.0          , -F.infinity),
3693             T(-0.0         , -F.infinity),
3694             T(1024         , 10         ),
3695             T(-2000        , 10         ),
3696             T(0x0.1p-127   , -131       ),
3697             T(0x0.01p-127  , -135       ),
3698             T(0x0.011p-127 , -135       ),
3699             T(F.nan        , F.nan      ),
3700             T(-F.nan       , F.nan      ),
3701             T(F.infinity   , F.infinity ),
3702             T(-F.infinity  , F.infinity ),
3703             T(F.min_normal , F.min_exp-1),
3704             T(-F.min_normal, F.min_exp-1),
3705             T(F.max        , F.max_exp-1),
3706             T(-F.max       , F.max_exp-1),
3707         ];
3708 
3709         foreach (elem; vals)
3710         {
3711             if (isNaN(elem[1]))
3712                 assert(isNaN(logb(elem[1])));
3713             else
3714                 assert(logb(elem[0]) == elem[1]);
3715         }
3716     }}
3717 }
3718 
3719 version (InlineAsm_X87_MSVC)
3720 private T logbAsm(T)(T x) @trusted pure nothrow @nogc
3721 {
3722     version (X86_64)
3723     {
3724         asm pure nothrow @nogc
3725         {
3726             naked                       ;
3727             fld     real ptr [RCX]      ;
3728             fxtract                     ;
3729             fstp    ST(0)               ;
3730             ret                         ;
3731         }
3732     }
3733     else
3734     {
3735         asm pure nothrow @nogc
3736         {
3737             fld     x                   ;
3738             fxtract                     ;
3739             fstp    ST(0)               ;
3740         }
3741     }
3742 }
3743 
3744 private T logbImpl(T)(T x) @trusted pure nothrow @nogc
3745 {
3746     import std.math.traits : isFinite;
3747 
3748     // Handle special cases.
3749     if (!isFinite(x))
3750         return x * x;
3751     if (x == 0)
3752         return -1 / (x * x);
3753 
3754     return ilogb(x);
3755 }
3756 
3757 /*************************************
3758  * Efficiently calculates x * 2$(SUPERSCRIPT n).
3759  *
3760  * scalbn handles underflow and overflow in
3761  * the same fashion as the basic arithmetic operators.
3762  *
3763  *      $(TABLE_SV
3764  *      $(TR $(TH x)                 $(TH scalb(x)))
3765  *      $(TR $(TD $(PLUSMNINF))      $(TD $(PLUSMNINF)) )
3766  *      $(TR $(TD $(PLUSMN)0.0)      $(TD $(PLUSMN)0.0) )
3767  *      )
3768  */
3769 pragma(inline, true)
3770 real scalbn(real x, int n) @safe pure nothrow @nogc { return _scalbn(x,n); }
3771 
3772 /// ditto
3773 pragma(inline, true)
3774 double scalbn(double x, int n) @safe pure nothrow @nogc { return _scalbn(x,n); }
3775 
3776 /// ditto
3777 pragma(inline, true)
3778 float scalbn(float x, int n) @safe pure nothrow @nogc { return _scalbn(x,n); }
3779 
3780 ///
3781 @safe pure nothrow @nogc unittest
3782 {
3783     assert(scalbn(0x1.2345678abcdefp0L, 999) == 0x1.2345678abcdefp999L);
3784     assert(scalbn(-real.infinity, 5) == -real.infinity);
3785     assert(scalbn(2.0,10) == 2048.0);
3786     assert(scalbn(2048.0f,-10) == 2.0f);
3787 }
3788 
3789 pragma(inline, true)
3790 private F _scalbn(F)(F x, int n)
3791 {
3792     import std.math.traits : isInfinity;
3793 
3794     if (__ctfe)
3795     {
3796         // Handle special cases.
3797         if (x == F(0.0) || isInfinity(x))
3798             return x;
3799     }
3800     return core.math.ldexp(x, n);
3801 }
3802 
3803 @safe pure nothrow @nogc unittest
3804 {
3805     // CTFE-able test
3806     static assert(scalbn(0x1.2345678abcdefp0L, 999) == 0x1.2345678abcdefp999L);
3807     static assert(scalbn(-real.infinity, 5) == -real.infinity);
3808     // Test with large exponent delta n where the result is in bounds but 2.0L ^^ n is not.
3809     enum initialExponent = real.min_exp + 2, resultExponent = real.max_exp - 2;
3810     enum int n = resultExponent - initialExponent;
3811     enum real x = 0x1.2345678abcdefp0L * (2.0L ^^ initialExponent);
3812     enum staticResult = scalbn(x, n);
3813     static assert(staticResult == 0x1.2345678abcdefp0L * (2.0L ^^ resultExponent));
3814     assert(scalbn(x, n) == staticResult);
3815 }
3816